5151import org .eclipse .rdf4j .sail .memory .MemoryStore ;
5252import org .eclipse .rdf4j .sail .shacl .ShaclSail .TransactionSettings .ValidationApproach ;
5353import org .eclipse .rdf4j .sail .shacl .ast .ContextWithShape ;
54+ import org .eclipse .rdf4j .sail .shacl .ast .Shape ;
5455import org .eclipse .rdf4j .sail .shacl .results .ValidationReport ;
5556import org .eclipse .rdf4j .sail .shacl .results .lazy .LazyValidationReport ;
5657import org .eclipse .rdf4j .sail .shacl .results .lazy .ValidationResultIterator ;
@@ -497,20 +498,24 @@ private ValidationReport validate(List<ContextWithShape> shapes, boolean validat
497498
498499 try {
499500 try (ConnectionsGroup connectionsGroup = getConnectionsGroup ()) {
500- return performValidation (shapes , validateEntireBaseSail , connectionsGroup );
501+ return performValidation (shapes , validateEntireBaseSail , connectionsGroup , this ,
502+ previousStateConnection );
501503 }
502504 } finally {
503505 rdfsSubClassOfReasoner = null ;
504506 }
505507
506508 }
507509
508- void prepareValidation (ValidationSettings validationSettings ) throws InterruptedException {
510+ void prepareValidation (ValidationSettings validationSettings , boolean requireRdfsSubClassReasoning )
511+ throws InterruptedException {
509512
510513 assert isValidationEnabled ();
511514
512- if (sail . isRdfsSubClassReasoning () ) {
515+ if (requireRdfsSubClassReasoning ) {
513516 rdfsSubClassOfReasoner = RdfsSubClassOfReasoner .createReasoner (this , validationSettings );
517+ } else {
518+ rdfsSubClassOfReasoner = null ;
514519 }
515520
516521 if (sail .isShutdown ()) {
@@ -528,15 +533,34 @@ void prepareValidation(ValidationSettings validationSettings) throws Interrupted
528533 }
529534
530535 ConnectionsGroup getConnectionsGroup () {
536+ return getConnectionsGroup (this , previousStateConnection , sail .isIncludeInferredStatements (),
537+ sail .isRdfsSubClassReasoning ());
538+ }
539+
540+ ConnectionsGroup getConnectionsGroup (SailConnection baseConnection , SailConnection previousStateConnection ,
541+ boolean includeInferredStatements , boolean useRdfsSubClassReasoning ) {
542+ RdfsSubClassOfReasoner reasoner = useRdfsSubClassReasoning ? rdfsSubClassOfReasoner : null ;
543+ ConnectionsGroup .RdfsSubClassOfReasonerProvider provider = reasoner == null ? null : () -> reasoner ;
531544
532- return new ConnectionsGroup (new VerySimpleRdfsBackwardsChainingConnection (this , rdfsSubClassOfReasoner ),
545+ return new ConnectionsGroup (
546+ new VerySimpleRdfsBackwardsChainingConnection (baseConnection , reasoner , includeInferredStatements ),
533547 previousStateConnection , addedStatements , removedStatements , stats ,
534- this ::getRdfsSubClassOfReasoner , transactionSettings , sail .sparqlValidation );
548+ provider , transactionSettings , sail .sparqlValidation );
549+ }
550+
551+ private boolean requiresRdfsSubClassReasoner (List <ContextWithShape > shapes ) {
552+ return shapes .stream ()
553+ .map (ContextWithShape ::getShape )
554+ .map (Shape ::getRdfsSubClassReasoningOverride )
555+ .anyMatch (Boolean .TRUE ::equals );
535556 }
536557
537558 private ValidationReport performValidation (List <ContextWithShape > shapes , boolean validateEntireBaseSail ,
538- ConnectionsGroup connectionsGroup ) throws InterruptedException {
559+ ConnectionsGroup connectionsGroup , SailConnection baseConnection , SailConnection previousStateConnection )
560+ throws InterruptedException {
539561 long beforeValidation = 0 ;
562+ boolean defaultIncludeInferredStatements = sail .isIncludeInferredStatements ();
563+ boolean defaultRdfsSubClassReasoning = sail .isRdfsSubClassReasoning ();
540564
541565 if (sail .isPerformanceLogging ()) {
542566 beforeValidation = System .currentTimeMillis ();
@@ -547,18 +571,36 @@ private ValidationReport performValidation(List<ContextWithShape> shapes, boolea
547571
548572 Stream <Callable <ValidationResultIterator >> callableStream = shapes
549573 .stream ()
550- .map (contextWithShapes -> new ShapeValidationContainer (
551- contextWithShapes .getShape (),
552- () -> contextWithShapes .getShape ()
553- .generatePlans (connectionsGroup ,
554- new ValidationSettings (contextWithShapes .getDataGraph (),
555- sail .isLogValidationPlans (), validateEntireBaseSail ,
556- sail .isPerformanceLogging ())),
557- sail .isGlobalLogValidationExecution (), sail .isLogValidationViolations (),
558- sail .getEffectiveValidationResultsLimitPerConstraint (), sail .isPerformanceLogging (),
559- sail .isLogValidationPlans (),
560- logger ,
561- connectionsGroup ))
574+ .map (contextWithShapes -> {
575+ Shape shape = contextWithShapes .getShape ();
576+ boolean shapeRdfsSubClassReasoning = shape
577+ .usesRdfsSubClassReasoning (defaultRdfsSubClassReasoning );
578+ boolean shapeIncludeInferredStatements = shape
579+ .usesIncludeInferredStatements (defaultIncludeInferredStatements );
580+
581+ boolean closeConnectionsGroup = false ;
582+ ConnectionsGroup shapeConnectionsGroup = connectionsGroup ;
583+ if (shapeRdfsSubClassReasoning != defaultRdfsSubClassReasoning
584+ || shapeIncludeInferredStatements != defaultIncludeInferredStatements ) {
585+ shapeConnectionsGroup = getConnectionsGroup (baseConnection , previousStateConnection ,
586+ shapeIncludeInferredStatements , shapeRdfsSubClassReasoning );
587+ closeConnectionsGroup = true ;
588+ }
589+ ConnectionsGroup planConnectionsGroup = shapeConnectionsGroup ;
590+
591+ return new ShapeValidationContainer (
592+ shape ,
593+ () -> shape .generatePlans (planConnectionsGroup ,
594+ new ValidationSettings (contextWithShapes .getDataGraph (),
595+ sail .isLogValidationPlans (), validateEntireBaseSail ,
596+ sail .isPerformanceLogging ())),
597+ sail .isGlobalLogValidationExecution (), sail .isLogValidationViolations (),
598+ sail .getEffectiveValidationResultsLimitPerConstraint (), sail .isPerformanceLogging (),
599+ sail .isLogValidationPlans (),
600+ logger ,
601+ shapeConnectionsGroup ,
602+ closeConnectionsGroup );
603+ })
562604
563605 .filter (ShapeValidationContainer ::hasPlanNode )
564606 .peek (s -> {
@@ -1071,24 +1113,28 @@ public void prepare() throws SailException {
10711113 return ;
10721114 }
10731115
1116+ List <ContextWithShape > shapesToValidate = shapesAfterRefresh != null ? shapesAfterRefresh : currentShapes ;
1117+ boolean requiresRdfsSubClassReasoner = sail .isRdfsSubClassReasoning ()
1118+ || requiresRdfsSubClassReasoner (shapesToValidate );
1119+
10741120 stats .setEmptyIncludingCurrentTransaction (ConnectionHelper .isEmpty (this ));
10751121
10761122 prepareValidation (
1077- new ValidationSettings (null , sail .isLogValidationPlans (), false , sail .isPerformanceLogging ()));
1123+ new ValidationSettings (null , sail .isLogValidationPlans (), false , sail .isPerformanceLogging ()),
1124+ requiresRdfsSubClassReasoner );
10781125
10791126 ValidationReport invalidTuples = null ;
10801127 if (useSerializableValidation ) {
10811128 synchronized (sail .singleConnectionMonitor ) {
10821129 if (!sail .usesSingleConnection ()) {
1083- invalidTuples = serializableValidation (
1084- shapesAfterRefresh != null ? shapesAfterRefresh : currentShapes );
1130+ invalidTuples = serializableValidation (shapesToValidate );
10851131 }
10861132 }
10871133 }
10881134
10891135 if (invalidTuples == null ) {
10901136 invalidTuples = validate (
1091- shapesAfterRefresh != null ? shapesAfterRefresh : currentShapes ,
1137+ shapesToValidate ,
10921138 shapesModifiedInCurrentTransaction || isBulkValidation ());
10931139 }
10941140
@@ -1152,10 +1198,8 @@ private boolean isBulkValidation() {
11521198 private ValidationReport serializableValidation (List <ContextWithShape > shapesAfterRefresh )
11531199 throws InterruptedException {
11541200 try {
1155- try (ConnectionsGroup connectionsGroup = new ConnectionsGroup (
1156- new VerySimpleRdfsBackwardsChainingConnection (serializableConnection , rdfsSubClassOfReasoner ), null ,
1157- addedStatements , removedStatements , stats , this ::getRdfsSubClassOfReasoner , transactionSettings ,
1158- sail .sparqlValidation )) {
1201+ try (ConnectionsGroup connectionsGroup = getConnectionsGroup (serializableConnection , null ,
1202+ sail .isIncludeInferredStatements (), sail .isRdfsSubClassReasoning ())) {
11591203
11601204 connectionsGroup .getBaseConnection ().begin (IsolationLevels .SNAPSHOT );
11611205 // actually force a transaction to start
@@ -1176,7 +1220,7 @@ private ValidationReport serializableValidation(List<ContextWithShape> shapesAft
11761220 serializableConnection .flush ();
11771221
11781222 return performValidation (shapesAfterRefresh , shapesModifiedInCurrentTransaction || isBulkValidation (),
1179- connectionsGroup );
1223+ connectionsGroup , serializableConnection , null );
11801224
11811225 } finally {
11821226 serializableConnection .rollback ();
0 commit comments