diff --git a/core/sail/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/ast/planNodes/AbstractPairwisePlanNode.java b/core/sail/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/ast/planNodes/AbstractPairwisePlanNode.java index 75be9b1778..cfac96a61c 100644 --- a/core/sail/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/ast/planNodes/AbstractPairwisePlanNode.java +++ b/core/sail/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/ast/planNodes/AbstractPairwisePlanNode.java @@ -36,12 +36,16 @@ import org.eclipse.rdf4j.sail.shacl.ast.paths.Path; import org.eclipse.rdf4j.sail.shacl.ast.paths.SimplePath; import org.eclipse.rdf4j.sail.shacl.results.ValidationResult; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * @author Håvard Ottestad */ abstract class AbstractPairwisePlanNode implements PlanNode { + private static final Logger logger = LoggerFactory.getLogger(AbstractPairwisePlanNode.class); + private final SailConnection connection; private final Resource[] dataGraph; private final IRI predicate; diff --git a/core/sail/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/ast/planNodes/DatatypeFilter.java b/core/sail/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/ast/planNodes/DatatypeFilter.java index 47192d3c5d..eba5429698 100644 --- a/core/sail/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/ast/planNodes/DatatypeFilter.java +++ b/core/sail/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/ast/planNodes/DatatypeFilter.java @@ -17,12 +17,16 @@ import org.eclipse.rdf4j.model.Literal; import org.eclipse.rdf4j.model.base.CoreDatatype; import org.eclipse.rdf4j.model.datatypes.XMLDatatypeUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * @author Håvard Ottestad */ public class DatatypeFilter extends FilterPlanNode { + private static final Logger logger = LoggerFactory.getLogger(DatatypeFilter.class); + private final IRI datatype; private final CoreDatatype.XSD xsdDatatype; private StackTraceElement[] stackTrace; @@ -37,17 +41,41 @@ public DatatypeFilter(PlanNode parent, IRI datatype) { @Override boolean checkTuple(Reference t) { if (!(t.get().getValue().isLiteral())) { + logger.debug("Tuple rejected because it's not a literal. Tuple: {}", t); return false; } Literal literal = (Literal) t.get().getValue(); if (xsdDatatype != null) { if (literal.getCoreDatatype() == xsdDatatype) { - return XMLDatatypeUtil.isValidValue(literal.stringValue(), xsdDatatype); + boolean isValid = XMLDatatypeUtil.isValidValue(literal.stringValue(), xsdDatatype); + if (isValid) { + logger.trace( + "Tuple accepted because its literal value is valid according to the rules for the datatype in the XSD spec. Actual datatype: {}, Expected datatype: {}, Tuple: {}", + literal.getDatatype(), xsdDatatype, t); + } else { + logger.debug( + "Tuple rejected because its literal value is invalid according to the rules for the datatype in the XSD spec. Actual datatype: {}, Expected datatype: {}, Tuple: {}", + literal.getDatatype(), xsdDatatype, t); + } + return isValid; } + logger.debug( + "Tuple rejected because literal's core datatype is not the expected datatype. Actual datatype: {}, Expected datatype: {}, Tuple: {}", + literal.getDatatype(), xsdDatatype, t); return false; } else { - return literal.getDatatype() == datatype || literal.getDatatype().equals(datatype); + boolean isEqual = literal.getDatatype() == datatype || literal.getDatatype().equals(datatype); + if (isEqual) { + logger.trace( + "Tuple accepted because literal's datatype is equal to the expected datatype. Actual datatype: {}, Expected datatype: {}, Tuple: {}", + literal.getDatatype(), datatype, t); + } else { + logger.debug( + "Tuple rejected because literal's datatype is not equal to the expected datatype. Actual datatype: {}, Expected datatype: {}, Tuple: {}", + literal.getDatatype(), datatype, t); + } + return isEqual; } } diff --git a/core/sail/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/ast/planNodes/ExternalFilterByQuery.java b/core/sail/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/ast/planNodes/ExternalFilterByQuery.java index 19bd975339..9336f1d426 100644 --- a/core/sail/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/ast/planNodes/ExternalFilterByQuery.java +++ b/core/sail/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/ast/planNodes/ExternalFilterByQuery.java @@ -91,10 +91,13 @@ boolean checkTuple(Reference t) { t.set(map.apply(t.get(), bindingSet.next())); } while (bindingSet.hasNext()); } + logger.trace("Tuple accepted because it matches the external query. Value: {}, Query: {}, Tuple: {}", + value, queryString, t); return true; } } - + logger.debug("Tuple rejected because it does not match the external query. Value: {}, Query: {}, Tuple: {}", + value, queryString, t); return false; } diff --git a/core/sail/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/ast/planNodes/GroupByCountFilter.java b/core/sail/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/ast/planNodes/GroupByCountFilter.java index 316c839465..2d95a21233 100644 --- a/core/sail/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/ast/planNodes/GroupByCountFilter.java +++ b/core/sail/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/ast/planNodes/GroupByCountFilter.java @@ -16,12 +16,16 @@ import org.apache.commons.text.StringEscapeUtils; import org.eclipse.rdf4j.common.iteration.CloseableIteration; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * @author Håvard Ottestad */ public class GroupByCountFilter implements PlanNode { + private static final Logger logger = LoggerFactory.getLogger(GroupByCountFilter.class); + private final Function filter; PlanNode parent; private boolean printed = false; @@ -74,7 +78,13 @@ private void calculateNext() { } if (!filter.apply(count)) { + logger.debug( + "Tuple rejected because its count does not pass the filter. Actual count: {}, Tuple: {}", + count, this.next); this.next = null; + } else { + logger.trace("Tuple accepted because its count passes the filter. Actual count: {}, Tuple: {}", + count, this.next); } } diff --git a/core/sail/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/ast/planNodes/LanguageInFilter.java b/core/sail/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/ast/planNodes/LanguageInFilter.java index ac2efb2d87..58736aee4c 100644 --- a/core/sail/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/ast/planNodes/LanguageInFilter.java +++ b/core/sail/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/ast/planNodes/LanguageInFilter.java @@ -19,12 +19,16 @@ import org.eclipse.rdf4j.model.Literal; import org.eclipse.rdf4j.model.util.Literals; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * @author Håvard Ottestad */ public class LanguageInFilter extends FilterPlanNode { + private static final Logger logger = LoggerFactory.getLogger(LanguageInFilter.class); + private final List languageRanges; private final Set lowerCaseLanguageIn; @@ -37,17 +41,22 @@ public LanguageInFilter(PlanNode parent, Set lowerCaseLanguageIn, List language = ((Literal) t.get().getValue()).getLanguage(); - if (!language.isPresent()) { + if (language.isEmpty()) { + logger.debug("Tuple rejected because it does not have a language tag. Tuple: {}", t); return false; } // early matching boolean languageMatches = language.map(String::toLowerCase).filter(lowerCaseLanguageIn::contains).isPresent(); if (languageMatches) { + logger.trace( + "Tuple accepted because its language tag (toLowerCase()) is in the language set. Actual language: {}, Language set: {}, Tuple: {}", + language.get(), lowerCaseLanguageIn, t); return true; } @@ -56,6 +65,9 @@ boolean checkTuple(Reference t) { for (String languageRange : languageRanges) { if (Literals.langMatches(langTag, languageRange)) { + logger.trace( + "Tuple accepted because its language tag matches the language range (BCP47). Actual language: {}, Language range: {}, Tuple: {}", + langTag, languageRange, t); return true; } } diff --git a/core/sail/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/ast/planNodes/NodeKindFilter.java b/core/sail/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/ast/planNodes/NodeKindFilter.java index 9190ea83c6..86526d93b9 100644 --- a/core/sail/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/ast/planNodes/NodeKindFilter.java +++ b/core/sail/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/ast/planNodes/NodeKindFilter.java @@ -15,12 +15,16 @@ import org.eclipse.rdf4j.model.Value; import org.eclipse.rdf4j.sail.shacl.ast.constraintcomponents.NodeKindConstraintComponent; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * @author Håvard Ottestad */ public class NodeKindFilter extends FilterPlanNode { + private static final Logger logger = LoggerFactory.getLogger(NodeKindFilter.class); + private final NodeKindConstraintComponent.NodeKind nodeKind; public NodeKindFilter(PlanNode parent, NodeKindConstraintComponent.NodeKind nodeKind) { @@ -32,28 +36,48 @@ public NodeKindFilter(PlanNode parent, NodeKindConstraintComponent.NodeKind node boolean checkTuple(Reference t) { Value value = t.get().getValue(); - /* - * BlankNode(SHACL.BLANK_NODE), IRI(SHACL.IRI), Literal(SHACL.LITERAL), BlankNodeOrIRI(SHACL.BLANK_NODE_OR_IRI), - * BlankNodeOrLiteral(SHACL.BLANK_NODE_OR_LITERAL), IRIOrLiteral(SHACL.IRI_OR_LITERAL), - */ switch (nodeKind) { case IRI: - return value.isIRI(); + if (value.isIRI()) { + logger.trace("Tuple accepted because its value is an IRI. Tuple: {}", t); + return true; + } + break; case Literal: - return value.isLiteral(); + if (value.isLiteral()) { + logger.trace("Tuple accepted because its value is a Literal. Tuple: {}", t); + return true; + } + break; case BlankNode: - return value.isBNode(); + if (value.isBNode()) { + logger.trace("Tuple accepted because its value is a BlankNode. Tuple: {}", t); + return true; + } + break; case IRIOrLiteral: - return value.isIRI() || value.isLiteral(); + if (value.isIRI() || value.isLiteral()) { + logger.trace("Tuple accepted because its value is an IRI or Literal. Tuple: {}", t); + return true; + } + break; case BlankNodeOrIRI: - return value.isBNode() || value.isIRI(); + if (value.isBNode() || value.isIRI()) { + logger.trace("Tuple accepted because its value is a BlankNode or IRI. Tuple: {}", t); + return true; + } + break; case BlankNodeOrLiteral: - return value.isBNode() || value.isLiteral(); + if (value.isBNode() || value.isLiteral()) { + logger.trace("Tuple accepted because its value is a BlankNode or Literal. Tuple: {}", t); + return true; + } + break; } - throw new IllegalStateException("Unknown nodeKind"); - + logger.debug("Tuple rejected because its value does not match the expected node kind. Tuple: {}", t); + return false; } @Override diff --git a/core/sail/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/ast/planNodes/PatternFilter.java b/core/sail/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/ast/planNodes/PatternFilter.java index be9b2abe69..ebef3b98dd 100644 --- a/core/sail/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/ast/planNodes/PatternFilter.java +++ b/core/sail/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/ast/planNodes/PatternFilter.java @@ -15,55 +15,65 @@ import java.util.regex.Pattern; import org.eclipse.rdf4j.model.Value; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * @author Håvard Ottestad */ public class PatternFilter extends FilterPlanNode { + private static final Logger logger = LoggerFactory.getLogger(PatternFilter.class); + private final Pattern pattern; public PatternFilter(PlanNode parent, String pattern, String flags) { super(parent); if (flags != null && !flags.isEmpty()) { - int flag = 0b0; if (flags.contains("i")) { flag = flag | Pattern.CASE_INSENSITIVE; + logger.trace("PatternFilter constructed with case insensitive flag"); } if (flags.contains("d")) { flag = flag | Pattern.UNIX_LINES; + logger.trace("PatternFilter constructed with UNIX lines flag"); } if (flags.contains("m")) { flag = flag | Pattern.MULTILINE; + logger.trace("PatternFilter constructed with multiline flag"); } if (flags.contains("s")) { flag = flag | Pattern.DOTALL; + logger.trace("PatternFilter constructed with dotall flag"); } if (flags.contains("u")) { flag = flag | Pattern.UNICODE_CASE; + logger.trace("PatternFilter constructed with unicode case flag"); } if (flags.contains("x")) { flag = flag | Pattern.COMMENTS; + logger.trace("PatternFilter constructed with comments flag"); } if (flags.contains("U")) { flag = flag | Pattern.UNICODE_CHARACTER_CLASS; + logger.trace("PatternFilter constructed with unicode character class flag"); } this.pattern = Pattern.compile(pattern, flag); + logger.trace("PatternFilter constructed with pattern: {} and flags: {}", pattern, flags); } else { this.pattern = Pattern.compile(pattern); - + logger.trace("PatternFilter constructed with pattern: {} and no flags", pattern); } - } @Override diff --git a/core/sail/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/ast/planNodes/Unique.java b/core/sail/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/ast/planNodes/Unique.java index 5cdeac1675..4ba1984e1e 100644 --- a/core/sail/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/ast/planNodes/Unique.java +++ b/core/sail/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/ast/planNodes/Unique.java @@ -61,6 +61,11 @@ public static PlanNode getInstance(PlanNode parent, boolean compress) { if (parent.isGuaranteedEmpty()) { return parent; } + + if (parent instanceof Unique && (!compress || ((Unique) parent).compress == compress)) { + return parent; + } + return new Unique(parent, compress); }