2222import org .eclipse .rdf4j .rio .RDFFormat ;
2323import org .eclipse .rdf4j .rio .helpers .BasicParserSettings ;
2424import org .eclipse .rdf4j .sail .memory .MemoryStore ;
25+ import org .neo4j .graphdb .GraphDatabaseService ;
2526import org .neo4j .graphdb .Transaction ;
2627import org .neo4j .logging .Log ;
2728
2829import java .io .IOException ;
2930import java .io .InputStream ;
3031import java .io .InputStreamReader ;
3132import java .util .*;
33+ import java .util .concurrent .TimeUnit ;
3234
3335import static n10s .graphconfig .GraphConfig .*;
3436import static n10s .graphconfig .Params .WKTLITERAL_URI ;
@@ -52,6 +54,7 @@ public class SHACLValidator {
5254 public static final String SHACL_VALUE_RANGE_CONSTRAINT_COMPONENT = "http://www.w3.org/ns/shacl#ValueRangeConstraintComponent" ;
5355 public static final String SHACL_LENGTH_CONSTRAINT_COMPONENT = "http://www.w3.org/ns/shacl#LengthConstraintComponent" ;
5456
57+
5558 String PROP_CONSTRAINT_QUERY = "prefix sh: <http://www.w3.org/ns/shacl#> \n " +
5659 "SELECT distinct ?ns ?ps ?path ?invPath ?rangeClass ?rangeKind ?datatype ?severity (coalesce(?pmsg, ?nmsg,\" \" ) as ?msg)\n " +
5760 "?targetClass ?targetIsQuery ?pattern ?maxCount ?minCount ?minInc ?minExc ?maxInc ?maxExc ?minStrLen \n " +
@@ -169,12 +172,15 @@ public class SHACLValidator {
169172 "} group by ?ns ?nmsg ?targetClass ?targetIsQuery" ;
170173
171174 private Transaction tx ;
175+ private GraphDatabaseService db ;
172176 private Log log ;
173177 private GraphConfig gc ;
174178
175- public SHACLValidator (Transaction transaction , Log l ) {
179+ public SHACLValidator (GraphDatabaseService db , Transaction transaction , Log l ) {
176180 this .tx = transaction ;
177181 this .log = l ;
182+ this .db = db ;
183+
178184 try {
179185 this .gc = new GraphConfig (tx );
180186 } catch (GraphConfigNotFound graphConfigNotFound ) {
@@ -186,7 +192,7 @@ public SHACLValidator(Transaction transaction, Log l) {
186192
187193
188194 protected ValidatorConfig compileValidations (Iterator <Map <String , Object >> constraints )
189- throws InvalidNamespacePrefixDefinitionInDB , UriNamespaceHasNoAssociatedPrefix {
195+ throws InvalidNamespacePrefixDefinitionInDB , UriNamespaceHasNoAssociatedPrefix {
190196
191197 ValidatorConfig vc = new ValidatorConfig ();
192198
@@ -206,7 +212,7 @@ protected ValidatorConfig compileValidations(Iterator<Map<String, Object>> const
206212 }
207213
208214 protected void processConstraint (Map <String , Object > theConstraint , ValidatorConfig vc )
209- throws InvalidNamespacePrefixDefinitionInDB , UriNamespaceHasNoAssociatedPrefix {
215+ throws InvalidNamespacePrefixDefinitionInDB , UriNamespaceHasNoAssociatedPrefix {
210216
211217 int constraintType ;
212218 String focusLabel = "" ;
@@ -223,6 +229,7 @@ protected void processConstraint(Map<String, Object> theConstraint, ValidatorCon
223229 } else if (theConstraint .containsKey ("appliesToQueryResult" ) ){
224230 //it's a query based constraint
225231 whereClause = (String ) theConstraint .get ("appliesToQueryResult" );
232+ validateWhereClause (whereClause );
226233 constraintType = QUERY_BASED_CONSTRAINT ;
227234 } else {
228235 throw new SHACLValidationException ("invalid constraint config" );
@@ -843,6 +850,18 @@ protected void processConstraint(Map<String, Object> theConstraint, ValidatorCon
843850
844851 }
845852
853+ private void validateWhereClause (String whereClause ) {
854+ try (Transaction tempTransaction = db .beginTx (50 , TimeUnit .MILLISECONDS )) {
855+
856+ tempTransaction .execute ("explain " + "match (focus) where " + whereClause + " return focus limit 1 " );
857+ } catch (Exception e ){
858+ throw new SHACLValidationException ("Invalid cypher expression: \" " + whereClause + "\" . The cypher fragment " +
859+ "in a sh:targetQuery element should form a valid query when embeeded in the following template: " +
860+ " \" match (focus) where <your cypher> return focus\" " );
861+ }
862+
863+ }
864+
846865 private String [] buildArgArray (int constraintType , List <String > classBasedParamList , List <String > queryBasedParamList ) {
847866 List <String > argsAsList = new ArrayList <>();
848867 argsAsList = constraintType == CLASS_BASED_CONSTRAINT ? classBasedParamList : queryBasedParamList ;
0 commit comments