This is an automated email from the ASF dual-hosted git repository.
andy pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/jena.git
The following commit(s) were added to refs/heads/main by this push:
new 1e075c9 JENA-2294: Handle SILENT for datasets with limited named
graph support
new b873622 Merge pull request #1214 from afs/jena2294-dsg-one
1e075c9 is described below
commit 1e075c9c52b74b0479a474813bed5b274c9ea2e8
Author: Andy Seaborne <[email protected]>
AuthorDate: Tue Mar 1 21:18:47 2022 +0000
JENA-2294: Handle SILENT for datasets with limited named graph support
---
.../jena/sparql/modify/UpdateEngineWorker.java | 460 +++++++++++----------
.../jena/sparql/modify/request/UpdateBinaryOp.java | 15 +-
.../jena/sparql/modify/request/UpdateLoad.java | 69 ++--
.../sparql/modify/request/UpdateWriterVisitor.java | 4 +-
.../sparql/modify/AbstractTestUpdateGraphMgt.java | 6 -
.../org/apache/jena/sparql/modify/TS_Update.java | 4 +-
...tMem.java => TestUpdateGraphMgtGeneralMem.java} | 2 +-
...phMgtMem.java => TestUpdateGraphMgtTxnMem.java} | 4 +-
.../jena/sparql/modify/TestUpdateSilent.java | 148 +++++++
jena-arq/testing/Update/empty.nt | 0
10 files changed, 450 insertions(+), 262 deletions(-)
diff --git
a/jena-arq/src/main/java/org/apache/jena/sparql/modify/UpdateEngineWorker.java
b/jena-arq/src/main/java/org/apache/jena/sparql/modify/UpdateEngineWorker.java
index ea80cf0..9c4380b 100644
---
a/jena-arq/src/main/java/org/apache/jena/sparql/modify/UpdateEngineWorker.java
+++
b/jena-arq/src/main/java/org/apache/jena/sparql/modify/UpdateEngineWorker.java
@@ -18,100 +18,111 @@
package org.apache.jena.sparql.modify;
-import static org.apache.jena.sparql.modify.TemplateLib.remapDefaultGraph ;
-import static org.apache.jena.sparql.modify.TemplateLib.template ;
-
-import java.util.ArrayList ;
-import java.util.Collection ;
-import java.util.Iterator ;
-import java.util.List ;
-
-import org.apache.jena.atlas.data.BagFactory ;
-import org.apache.jena.atlas.data.DataBag ;
-import org.apache.jena.atlas.data.ThresholdPolicy ;
-import org.apache.jena.atlas.data.ThresholdPolicyFactory ;
-import org.apache.jena.atlas.iterator.Iter ;
-import org.apache.jena.atlas.lib.Pair ;
+import static org.apache.jena.sparql.modify.TemplateLib.remapDefaultGraph;
+import static org.apache.jena.sparql.modify.TemplateLib.template;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.jena.atlas.data.BagFactory;
+import org.apache.jena.atlas.data.DataBag;
+import org.apache.jena.atlas.data.ThresholdPolicy;
+import org.apache.jena.atlas.data.ThresholdPolicyFactory;
+import org.apache.jena.atlas.iterator.Iter;
+import org.apache.jena.atlas.lib.Pair;
import org.apache.jena.atlas.logging.Log;
import org.apache.jena.atlas.web.TypedInputStream;
-import org.apache.jena.graph.Graph ;
-import org.apache.jena.graph.GraphUtil ;
-import org.apache.jena.graph.Node ;
-import org.apache.jena.query.Query ;
-import org.apache.jena.query.QueryExecutionFactory ;
-import org.apache.jena.riot.Lang;
-import org.apache.jena.riot.RDFDataMgr;
-import org.apache.jena.riot.RDFLanguages;
-import org.apache.jena.riot.RDFParser;
-import org.apache.jena.sparql.ARQInternalErrorException ;
-import org.apache.jena.sparql.core.* ;
-import org.apache.jena.sparql.engine.Plan ;
-import org.apache.jena.sparql.engine.binding.Binding ;
-import org.apache.jena.sparql.engine.binding.BindingRoot ;
-import org.apache.jena.sparql.graph.GraphFactory ;
-import org.apache.jena.sparql.graph.GraphOps ;
-import org.apache.jena.sparql.modify.request.* ;
-import org.apache.jena.sparql.syntax.Element ;
-import org.apache.jena.sparql.syntax.ElementGroup ;
-import org.apache.jena.sparql.syntax.ElementNamedGraph ;
-import org.apache.jena.sparql.syntax.ElementTriplesBlock ;
+import org.apache.jena.graph.Graph;
+import org.apache.jena.graph.GraphUtil;
+import org.apache.jena.graph.Node;
+import org.apache.jena.query.Query;
+import org.apache.jena.query.QueryExecutionFactory;
+import org.apache.jena.riot.*;
+import org.apache.jena.sparql.ARQInternalErrorException;
+import org.apache.jena.sparql.core.*;
+import org.apache.jena.sparql.engine.Plan;
+import org.apache.jena.sparql.engine.binding.Binding;
+import org.apache.jena.sparql.engine.binding.BindingRoot;
+import org.apache.jena.sparql.graph.GraphFactory;
+import org.apache.jena.sparql.graph.GraphOps;
+import org.apache.jena.sparql.modify.request.*;
+import org.apache.jena.sparql.syntax.Element;
+import org.apache.jena.sparql.syntax.ElementGroup;
+import org.apache.jena.sparql.syntax.ElementNamedGraph;
+import org.apache.jena.sparql.syntax.ElementTriplesBlock;
import org.apache.jena.sparql.system.SerializationFactoryFinder;
-import org.apache.jena.sparql.util.Context ;
-import org.apache.jena.update.UpdateException ;
+import org.apache.jena.sparql.util.Context;
+import org.apache.jena.update.UpdateException;
-/** Implementation of general purpose update request execution */
+/** Implementation of general purpose update request execution */
public class UpdateEngineWorker implements UpdateVisitor
{
- protected final DatasetGraph datasetGraph ;
- protected final boolean alwaysSilent = true ;
- protected final Binding inputBinding; // Used for UpdateModify only
- protected final Context context ;
+ protected final DatasetGraph datasetGraph;
+ protected final boolean autoSilent = true; // DROP and CREATE
+ protected final Binding inputBinding; // Used for UpdateModify only:
substitution is better.
+ protected final Context context;
public UpdateEngineWorker(DatasetGraph datasetGraph, Binding inputBinding,
Context context) {
- this.datasetGraph = datasetGraph ;
- this.inputBinding = inputBinding ;
- this.context = context ;
+ this.datasetGraph = datasetGraph;
+ this.inputBinding = inputBinding;
+ this.context = context;
}
@Override
public void visit(UpdateDrop update)
- { execDropClear(update, false) ; }
+ { execDropClear(update, false); }
@Override
public void visit(UpdateClear update)
- { execDropClear(update, true) ; }
+ { execDropClear(update, true); }
protected void execDropClear(UpdateDropClear update, boolean isClear) {
if ( update.isAll() ) {
- execDropClear(update, null, true); // Always clear.
+ // ALL
+ execDropClear(update, null, true); // DROP is CLEAR on DEFAULT.
execDropClearAllNamed(update, isClear);
} else if ( update.isAllNamed() )
+ // NAMED
execDropClearAllNamed(update, isClear);
else if ( update.isDefault() )
- execDropClear(update, null, true);
+ // DEFAULT
+ execDropClear(update, null, true); // DROP is CLEAR on DEFAULT.
else if ( update.isOneGraph() )
+ // GRAPH iri
execDropClear(update, update.getGraph(), isClear);
else
+ // Error: should not happen.
throw new ARQInternalErrorException("Target is undefined: " +
update.getTarget());
}
protected void execDropClear(UpdateDropClear update, Node g, boolean
isClear) {
- if ( !alwaysSilent ) {
- if ( g != null && !datasetGraph.containsGraph(g) &&
!update.isSilent() )
- error("No such graph: " + g);
- }
-
- if ( isClear ) {
- if ( g == null || datasetGraph.containsGraph(g) )
- graph(datasetGraph, g).clear();
- } else
- datasetGraph.removeGraph(g);
+ // DROP always works.
+ // """
+ // After successful completion of this operation, the specified
graphs are no
+ // longer available for further graph update operations.
+ // """
+ boolean auto = autoSilent && !isClear;
+ executeOperation( auto || update.isSilent(), () -> {
+ if ( g != null && !datasetGraph.containsGraph(g) )
+ throw errorEx("No such graph: " + g);
+ if ( isClear ) {
+ if ( g == null || datasetGraph.containsGraph(g) )
+ graphOrThrow(datasetGraph, g).clear();
+ } else {
+ try {
+ datasetGraph.removeGraph(g);
+ } catch (UnsupportedOperationException ex) {
+ throw new UpdateException("DROP of named graph not
supported");
+ }
+ }
+ });
}
protected void execDropClearAllNamed(UpdateDropClear update, boolean
isClear) {
// Avoid ConcurrentModificationException
List<Node> list = Iter.toList(datasetGraph.listGraphNodes());
-
for ( Node gn : list )
execDropClear(update, gn, isClear);
}
@@ -122,155 +133,162 @@ public class UpdateEngineWorker implements UpdateVisitor
if ( g == null )
return;
if ( datasetGraph.containsGraph(g) ) {
- if ( !alwaysSilent && !update.isSilent() )
- error("Graph store already contains graph : " + g);
+ if ( !autoSilent && !update.isSilent() )
+ throw errorEx("Graph store already contains graph : " + g);
return;
}
- // In-memory specific
- datasetGraph.addGraph(g, GraphFactory.createDefaultGraph());
+ // To be general, add an empty graph.
+ // Most datasets implementations have "auto-create" so CREATE is a
no-op.
+ // But dataset of separate graphs needs this (check!) to trigger the
graph.
+ // This is "copy-in" of zero triples.
+ executeOperation(update.isSilent(), () ->
+ { try { datasetGraph.addGraph(g,
GraphFactory.createDefaultGraph()); }
+ catch(UnsupportedOperationException ex) {
+ throw new UpdateException("CREATE of named graph not
supported");
+ }
+ });
}
@Override
public void visit(UpdateLoad update) {
- // LOAD SILENT? iri ( INTO GraphRef )?
+ // LOAD SILENT? iri ( INTO GraphRef )?
String source = update.getSource();
Node dest = update.getDest();
- Graph graph = graph(datasetGraph, dest);
- // We must load buffered if silent so that the dataset graph sees
- // all or no triples/quads when there is a parse error
- // (no nested transaction abort).
- boolean loadBuffered = update.getSilent() || !
datasetGraph.supportsTransactionAbort() ;
- try {
- if ( dest == null ) {
- // LOAD SILENT? iri
- // Quads accepted (extension).
+ executeOperation(update.isSilent(), ()->{
+ Graph graph = graphOrThrow(datasetGraph, dest);
+ // We must load buffered if silent so that the dataset graph sees
+ // all or no triples/quads when there is a parse error
+ // (no nested transaction abort).
+ try {
+ boolean loadBuffered = update.isSilent() || !
datasetGraph.supportsTransactionAbort();
+ if ( dest == null ) {
+ // LOAD SILENT? iri
+ // Quads accepted (extension).
+ if ( loadBuffered ) {
+ DatasetGraph dsg2 = DatasetGraphFactory.create();
+ RDFDataMgr.read(dsg2, source);
+ dsg2.find().forEachRemaining(datasetGraph::add);
+ } else {
+ RDFDataMgr.read(datasetGraph, source);
+ }
+ return;
+ }
+ // LOAD SILENT? iri INTO GraphRef
+ // Load triples. To give a decent error message and also not
have the usual
+ // parser behaviour of just selecting default graph triples
when the
+ // destination is a graph, we need to do the same steps as
RDFParser.parseURI,
+ // with different checking.
+ TypedInputStream input = RDFDataMgr.open(source);
+ String contentType = input.getContentType();
+ Lang lang = RDFDataMgr.determineLang(source, contentType,
Lang.TTL);
+ if ( lang == null )
+ throw new UpdateException("Failed to determine the syntax
for '"+source+"'");
+ if ( ! RDFLanguages.isTriples(lang) )
+ throw new UpdateException("Attempt to load quads into a
graph");
+ RDFParser parser = RDFParser
+ .source(input.getInputStream())
+ .forceLang(lang)
+ .build();
if ( loadBuffered ) {
- DatasetGraph dsg2 = DatasetGraphFactory.create();
- RDFDataMgr.read(dsg2, source);
- dsg2.find().forEachRemaining(datasetGraph::add);
+ Graph g = GraphFactory.createGraphMem();
+ parser.parse(g);
+ GraphUtil.addInto(graph, g);
} else {
- RDFDataMgr.read(datasetGraph, source);
+ parser.parse(graph);
+ }
+ } catch (RiotException ex) {
+ if ( !update.isSilent() ) {
+ throw new UpdateException("Failed to LOAD '" + source + "'
:: " + ex.getMessage(), ex);
}
- return ;
- }
- // LOAD SILENT? iri INTO GraphRef
- // Load triples. To give a decent error message and also not have
the usual
- // parser behaviour of just selecting default graph triples when
the
- // destination is a graph, we need to do the same steps as
RDFParser.parseURI,
- // with different checking.
- TypedInputStream input = RDFDataMgr.open(source);
- String contentType = input.getContentType();
- Lang lang = RDFDataMgr.determineLang(source, contentType,
Lang.TTL);
- if ( lang == null )
- throw new UpdateException("Failed to determine the syntax for
'"+source+"'");
- if ( ! RDFLanguages.isTriples(lang) )
- throw new UpdateException("Attempt to load quads into a
graph");
- RDFParser parser = RDFParser
- .source(input.getInputStream())
- .forceLang(lang)
- .build();
- if ( loadBuffered ) {
- Graph g = GraphFactory.createGraphMem();
- parser.parse(g);
- GraphUtil.addInto(graph, g);
- } else {
- parser.parse(graph);
- }
- } catch (RuntimeException ex) {
- if ( !update.getSilent() ) {
- if ( ex instanceof UpdateException )
- throw ex;
- throw new UpdateException("Failed to LOAD '" + source + "' ::
" + ex.getMessage(), ex);
}
- }
+ });
}
@Override
public void visit(UpdateAdd update) {
- // ADD SILENT? (DEFAULT or GRAPH) TO (DEFAULT or GRAPH)
- if ( !validBinaryGraphOp(update) )
- return;
- if ( update.getSrc().equals(update.getDest()) )
- return;
- // Different source and destination.
- gsAddTriples(datasetGraph, update.getSrc(), update.getDest());
+ executeOperation(update.isSilent(), ()->{
+ // ADD SILENT? (DEFAULT or GRAPH) TO (DEFAULT or GRAPH)
+ validateBinaryGraphOp(update);
+ if ( update.getSrc().equals(update.getDest()) )
+ return;
+ // Different source and destination.
+ gsAddTriples(datasetGraph, update.getSrc(), update.getDest());
+ });
}
@Override
public void visit(UpdateCopy update) {
- // COPY SILENT? (DEFAULT or GRAPH) TO (DEFAULT or GRAPH)
- if ( !validBinaryGraphOp(update) )
- return;
- if ( update.getSrc().equals(update.getDest()) )
- return;
- gsCopy(datasetGraph, update.getSrc(), update.getDest(),
update.getSilent());
+ executeOperation(update.isSilent(), ()->{
+ // COPY SILENT? (DEFAULT or GRAPH) TO (DEFAULT or GRAPH)
+ validateBinaryGraphOp(update);
+ if ( update.getSrc().equals(update.getDest()) )
+ // Same source and destination.
+ return;
+ // Different source and destination.
+ gsCopy(datasetGraph, update.getSrc(), update.getDest());
+ });
}
@Override
public void visit(UpdateMove update) {
- // MOVE SILENT? (DEFAULT or GRAPH) TO (DEFAULT or GRAPH)
- if ( !validBinaryGraphOp(update) )
- return;
- if ( update.getSrc().equals(update.getDest()) )
- return;
- // MOVE (DEFAULT or GRAPH) TO (DEFAULT or GRAPH)
- // Difefrent source and destination.
- gsCopy(datasetGraph, update.getSrc(), update.getDest(),
update.getSilent());
- gsDrop(datasetGraph, update.getSrc(), true);
- }
-
- private boolean validBinaryGraphOp(UpdateBinaryOp update) {
+ executeOperation(update.isSilent(), ()->{
+ // MOVE SILENT? (DEFAULT or GRAPH) TO (DEFAULT or GRAPH)
+ validateBinaryGraphOp(update);
+ if ( update.getSrc().equals(update.getDest()) )
+ // Same source and destination.
+ return;
+ // Different source and destination.
+ gsCopy(datasetGraph, update.getSrc(), update.getDest());
+ gsDrop(datasetGraph, update.getSrc());
+ });
+ }
+
+ /** Test whether the operation of G1 to G2 is valid */
+ private void validateBinaryGraphOp(UpdateBinaryOp update) {
if ( update.getSrc().isDefault() )
- return true;
-
+ return;
if ( update.getSrc().isOneNamedGraph() ) {
Node gn = update.getSrc().getGraph();
- if ( !datasetGraph.containsGraph(gn) ) {
- if ( !update.getSilent() )
- error("No such graph: " + gn);
- return false;
- }
- return true;
+ if ( !datasetGraph.containsGraph(gn) )
+ throw errorEx("No such graph: " + gn);
}
- error("Invalid source target for oepration; " + update.getSrc());
- return false;
+ throw errorEx("Invalid source target for operation; " +
update.getSrc());
}
// ----
// Core operations
/** Copy from src to dst : copy overwrites (= deletes) the old contents */
- protected static void gsCopy(DatasetGraph dsg, Target src, Target dest,
boolean isSilent)
- {
- if ( dest.equals(src) )
- return ;
- gsClear(dsg, dest, true) ;
- gsAddTriples(dsg, src, dest) ;
+ protected static void gsCopy(DatasetGraph dsg, Target src, Target dest) {
+ if ( dest.equals(src) )
+ return;
+ gsClear(dsg, dest);
+ gsAddTriples(dsg, src, dest);
}
/** Add triples from src to dest */
protected static void gsAddTriples(DatasetGraph dsg, Target src, Target
dest) {
- Graph gSrc = graph(dsg, src);
- Graph gDest = graph(dsg, dest);
+ Graph gSrc = graphOrThrow(dsg, src);
+ Graph gDest = graphOrThrow(dsg, dest);
GraphOps.addAll(gDest, gSrc.find());
}
/** Clear target */
- protected static void gsClear(DatasetGraph dsg, Target target, boolean
isSilent) {
+ protected static void gsClear(DatasetGraph dsg, Target target) {
// No create - we tested earlier.
- Graph g = graph(dsg, target);
+ Graph g = graphOrThrow(dsg, target);
g.clear();
}
/** Remove the target graph */
- protected static void gsDrop(DatasetGraph dsg, Target target, boolean
isSilent) {
+ protected static void gsDrop(DatasetGraph dsg, Target target) {
if ( target.isDefault() )
dsg.getDefaultGraph().clear();
else
dsg.removeGraph(target.getGraph());
}
-
+
// ----
-
+
@Override
public void visit(UpdateDataInsert update) {
for ( Quad quad : update.getQuads() )
@@ -285,16 +303,16 @@ public class UpdateEngineWorker implements UpdateVisitor
@Override
public void visit(UpdateDeleteWhere update) {
- List<Quad> quads = update.getQuads() ;
+ List<Quad> quads = update.getQuads();
// Removed from SPARQL : Convert bNodes to named variables first.
- //quads = convertBNodesToVariables(quads) ;
-
+ //quads = convertBNodesToVariables(quads);
+
// Convert quads to a pattern.
- Element el = elementFromQuads(quads) ;
-
+ Element el = elementFromQuads(quads);
+
// Decided to serialize the bindings, but could also have decided to
// serialize the quads after applying the template instead.
-
+
ThresholdPolicy<Binding> policy =
ThresholdPolicyFactory.policyFromContext(datasetGraph.getContext());
DataBag<Binding> db = BagFactory.newDefaultBag(policy,
SerializationFactoryFinder.bindingSerializationFactory());
try {
@@ -310,7 +328,7 @@ public class UpdateEngineWorker implements UpdateVisitor
db.close();
}
}
-
+
@Override
public void visit(UpdateModify update) {
Node withGraph = update.getWithIRI();
@@ -332,22 +350,22 @@ public class UpdateEngineWorker implements UpdateVisitor
// but the rewrite with ElementNamedGraph is closer to SPARQL.
// Better, treat as
// WHERE { GRAPH <with> { ... } }
- // This is the SPARQL wording (which is a bit loose).
- elt = new ElementNamedGraph(withGraph, elt) ;
+ // This is the SPARQL wording (which is a bit loose).
+ elt = new ElementNamedGraph(withGraph, elt);
}
// WITH :
// The quads from deletion/insertion are altered when streamed
- // into the templates later on.
-
+ // into the templates later on.
+
// -------------------
-
+
if ( dsg == null )
- dsg = datasetGraph ;
-
- Query query = elementToQuery(elt) ;
+ dsg = datasetGraph;
+
+ Query query = elementToQuery(elt);
ThresholdPolicy<Binding> policy =
ThresholdPolicyFactory.policyFromContext(datasetGraph.getContext());
- DataBag<Binding> db = BagFactory.newDefaultBag(policy,
SerializationFactoryFinder.bindingSerializationFactory()) ;
+ DataBag<Binding> db = BagFactory.newDefaultBag(policy,
SerializationFactoryFinder.bindingSerializationFactory());
try {
Iterator<Binding> bindings = evalBindings(query, dsg,
inputBinding, context);
@@ -382,7 +400,7 @@ public class UpdateEngineWorker implements UpdateVisitor
}
private Graph graphOrDummy(DatasetGraph dsg, Node gn) {
- Graph g = graph(datasetGraph, gn);
+ Graph g = graphOrThrow(datasetGraph, gn);
if ( g == null )
g = GraphFactory.createGraphMem();
return g;
@@ -412,7 +430,7 @@ public class UpdateEngineWorker implements UpdateVisitor
}
// JENA-1059 : optimization : process templates for ground triples and do
these once.
- // execDelete ; execInsert
+ // execDelete; execInsert
// Quads involving only IRIs and literals do not change from binding to
// binding so any inserts, rather than repeatedly if they are going to be
// done at all. Note bNodes (if legal at this point) change from template
@@ -420,20 +438,20 @@ public class UpdateEngineWorker implements UpdateVisitor
/**
* Split quads into ground terms (no variables) and templated quads.
* @param quads
- * @return Pair of (ground quads, templated quads)
+ * @return Pair of (ground quads, templated quads)
*/
private static Pair<List<Quad>, List<Quad>> split(Collection<Quad> quads) {
// Guess size.
- // Pre-size in case large (i.e. 10K+).
- List<Quad> constQuads = new ArrayList<>(quads.size()) ;
+ // Pre-size in case large (i.e. 10K+).
+ List<Quad> constQuads = new ArrayList<>(quads.size());
// ... in which case we assume the templated triples are small /
non-existent.
- List<Quad> templateQuads = new ArrayList<>() ;
+ List<Quad> templateQuads = new ArrayList<>();
quads.forEach((q)-> {
if ( constQuad(q))
- constQuads.add(q) ;
+ constQuads.add(q);
else
- templateQuads.add(q) ;
- }) ;
+ templateQuads.add(q);
+ });
return Pair.create(constQuads, templateQuads);
}
@@ -441,41 +459,41 @@ public class UpdateEngineWorker implements UpdateVisitor
return constTerm(quad.getGraph()) && constTerm(quad.getSubject())
&&
constTerm(quad.getPredicate()) && constTerm(quad.getObject());
}
-
+
private static boolean constTerm(Node n) {
- return n.isURI() || n.isLiteral() ;
+ return n.isURI() || n.isLiteral();
}
protected static void execDelete(DatasetGraph dsg, List<Quad> quads, Node
dftGraph, Iterator<Binding> bindings) {
- Pair<List<Quad>, List<Quad>> p = split(quads) ;
- execDelete(dsg, p.getLeft(), p.getRight(), dftGraph, bindings) ;
+ Pair<List<Quad>, List<Quad>> p = split(quads);
+ execDelete(dsg, p.getLeft(), p.getRight(), dftGraph, bindings);
}
-
+
protected static void execDelete(DatasetGraph dsg, List<Quad> onceQuads,
List<Quad> templateQuads, Node dftGraph, Iterator<Binding> bindings) {
if ( onceQuads != null && bindings.hasNext() ) {
- onceQuads = remapDefaultGraph(onceQuads, dftGraph) ;
- onceQuads.forEach(q->deleteFromDatasetGraph(dsg, q)) ;
+ onceQuads = remapDefaultGraph(onceQuads, dftGraph);
+ onceQuads.forEach(q->deleteFromDatasetGraph(dsg, q));
}
- Iterator<Quad> it = template(templateQuads, dftGraph, bindings) ;
+ Iterator<Quad> it = template(templateQuads, dftGraph, bindings);
if ( it == null )
- return ;
- it.forEachRemaining(q->deleteFromDatasetGraph(dsg, q)) ;
+ return;
+ it.forEachRemaining(q->deleteFromDatasetGraph(dsg, q));
}
protected static void execInsert(DatasetGraph dsg, List<Quad> quads, Node
dftGraph, Iterator<Binding> bindings) {
- Pair<List<Quad>, List<Quad>> p = split(quads) ;
- execInsert(dsg, p.getLeft(), p.getRight(), dftGraph, bindings) ;
+ Pair<List<Quad>, List<Quad>> p = split(quads);
+ execInsert(dsg, p.getLeft(), p.getRight(), dftGraph, bindings);
}
-
+
protected static void execInsert(DatasetGraph dsg, List<Quad> onceQuads,
List<Quad> templateQuads, Node dftGraph, Iterator<Binding> bindings) {
if ( onceQuads != null && bindings.hasNext() ) {
- onceQuads = remapDefaultGraph(onceQuads, dftGraph) ;
- onceQuads.forEach((q)->addToDatasetGraph(dsg, q)) ;
+ onceQuads = remapDefaultGraph(onceQuads, dftGraph);
+ onceQuads.forEach((q)->addToDatasetGraph(dsg, q));
}
- Iterator<Quad> it = template(templateQuads, dftGraph, bindings) ;
+ Iterator<Quad> it = template(templateQuads, dftGraph, bindings);
if ( it == null )
- return ;
- it.forEachRemaining((q)->addToDatasetGraph(dsg, q)) ;
+ return;
+ it.forEachRemaining((q)->addToDatasetGraph(dsg, q));
}
// Catch all individual adds of quads
@@ -484,7 +502,7 @@ public class UpdateEngineWorker implements UpdateVisitor
if ( quad.isLegalAsData() )
datasetGraph.add(quad);
// Else drop.
- // Log.warn(UpdateEngineWorker.class, "Bad quad as data: "+quad) ;
+ // Log.warn(UpdateEngineWorker.class, "Bad quad as data: "+quad);
}
// Catch all individual deletes of quads
@@ -525,23 +543,43 @@ public class UpdateEngineWorker implements UpdateVisitor
return toReturn;
}
- protected static Graph graph(DatasetGraph datasetGraph, Node gn) {
- if ( gn == null || gn == Quad.defaultGraphNodeGenerated )
+ /**
+ * Execute.
+ * <br/>
+ * Return true if successful.
+ * <br/>
+ *
+ * Otherwise if not silent: throw UpdateException, if silent, return false
+ */
+ private boolean executeOperation(boolean isSilent, Runnable action) {
+ try {
+ action.run();
+ return true;
+ } catch (UpdateException ex) {
+ if ( isSilent )
+ return false;
+ throw ex;
+ }
+ }
+
+ protected static Graph graphOrThrow(DatasetGraph datasetGraph, Node gn) {
+ if ( gn == null || Quad.isDefaultGraph(gn) )
return datasetGraph.getDefaultGraph();
- else
- return datasetGraph.getGraph(gn);
+ Graph g = datasetGraph.getGraph(gn);
+ if ( g == null )
+ throw errorEx("No such graph in this dataset: "+gn);
+ return g;
}
- protected static Graph graph(DatasetGraph datasetGraph, Target target) {
+ protected static Graph graphOrThrow(DatasetGraph datasetGraph, Target
target) {
if ( target.isDefault() )
return datasetGraph.getDefaultGraph();
if ( target.isOneNamedGraph() )
- return graph(datasetGraph, target.getGraph());
- error("Target does not name one graph: " + target);
- return null;
+ return graphOrThrow(datasetGraph, target.getGraph());
+ throw errorEx("Target does not name one graph: " + target);
}
- protected static void error(String msg) {
- throw new UpdateException(msg);
+ protected static UpdateException errorEx(String msg) {
+ return new UpdateException(msg);
}
}
diff --git
a/jena-arq/src/main/java/org/apache/jena/sparql/modify/request/UpdateBinaryOp.java
b/jena-arq/src/main/java/org/apache/jena/sparql/modify/request/UpdateBinaryOp.java
index 73b5446..91b4644 100644
---
a/jena-arq/src/main/java/org/apache/jena/sparql/modify/request/UpdateBinaryOp.java
+++
b/jena-arq/src/main/java/org/apache/jena/sparql/modify/request/UpdateBinaryOp.java
@@ -32,7 +32,7 @@ public abstract class UpdateBinaryOp extends Update
{
checkTarget(src) ;
checkTarget(dest) ;
- this.src = src ;
+ this.src = src ;
this.dest = dest ;
this.silent = silent ;
}
@@ -40,15 +40,20 @@ public abstract class UpdateBinaryOp extends Update
private static void checkTarget(Target target)
{
if ( ! target.isDefault() && ! target.isOneNamedGraph() )
- throw new ARQException("Illegal target: must identify a single
graph: "+target) ;
+ throw new ARQException("Illegal target: must identify a single
graph: "+target) ;
}
public Target getSrc() { return src ; }
public Target getDest() { return dest ; }
-
- public boolean getSilent() { return silent ; }
-
+
+ /**
+ * @deprecated use {@link #isSilent}
+ */
+ @Deprecated
+ public boolean getSilent() { return isSilent() ; }
+ public boolean isSilent() { return silent ; }
+
@Override
final
public boolean equalTo(Update obj, NodeIsomorphismMap isoMap) {
diff --git
a/jena-arq/src/main/java/org/apache/jena/sparql/modify/request/UpdateLoad.java
b/jena-arq/src/main/java/org/apache/jena/sparql/modify/request/UpdateLoad.java
index efb605b..27e2665 100644
---
a/jena-arq/src/main/java/org/apache/jena/sparql/modify/request/UpdateLoad.java
+++
b/jena-arq/src/main/java/org/apache/jena/sparql/modify/request/UpdateLoad.java
@@ -20,61 +20,62 @@ package org.apache.jena.sparql.modify.request;
import java.util.Objects;
-import org.apache.jena.graph.Node ;
-import org.apache.jena.graph.NodeFactory ;
-import org.apache.jena.sparql.util.Iso ;
-import org.apache.jena.sparql.util.NodeIsomorphismMap ;
-import org.apache.jena.update.Update ;
+import org.apache.jena.graph.Node;
+import org.apache.jena.graph.NodeFactory;
+import org.apache.jena.sparql.util.Iso;
+import org.apache.jena.sparql.util.NodeIsomorphismMap;
+import org.apache.jena.update.Update;
public class UpdateLoad extends Update
{
- private final String source ;
- private final Node dest ;
- private boolean silent ;
-
+ private final String source;
+ private final Node dest;
+ private boolean silent;
- public UpdateLoad(String source, String dest)
- {
- this(source, NodeFactory.createURI(dest), false) ;
+
+ public UpdateLoad(String source, String dest) {
+ this(source, NodeFactory.createURI(dest), false);
}
-
- public UpdateLoad(String source, String dest, boolean silent)
- {
- this(source, NodeFactory.createURI(dest), silent) ;
+
+ public UpdateLoad(String source, String dest, boolean silent) {
+ this(source, NodeFactory.createURI(dest), silent);
}
- public UpdateLoad(String source, Node dest)
- {
- this(source, dest, false) ;
+ public UpdateLoad(String source, Node dest) {
+ this(source, dest, false);
}
- public UpdateLoad(String source, Node dest, boolean silent)
- {
- this.source = source ;
- this.dest = dest ;
- this.silent = silent ;
+ public UpdateLoad(String source, Node dest, boolean silent) {
+ this.source = source;
+ this.dest = dest;
+ this.silent = silent;
}
- public String getSource() { return source ; }
- public Node getDest() { return dest ; }
- public boolean getSilent() { return silent ; }
+ public String getSource() { return source; }
+ public Node getDest() { return dest; }
+ /**
+ * @deprecated use {@link #isSilent}
+ */
+ @Deprecated
+ public boolean getSilent() { return isSilent(); }
+ public boolean isSilent() { return silent; }
@Override
public void visit(UpdateVisitor visitor)
- { visitor.visit(this) ; }
+ { visitor.visit(this); }
@Override
public boolean equalTo(Update obj, NodeIsomorphismMap isoMap) {
if (this == obj)
- return true ;
+ return true;
if (obj == null)
- return false ;
+ return false;
if (getClass() != obj.getClass())
- return false ;
- UpdateLoad other = (UpdateLoad)obj ;
- return
+ return false;
+ UpdateLoad other = (UpdateLoad)obj;
+ return
silent == other.silent &&
Objects.equals(source, other.source) &&
- Iso.nodeIso(dest, other.dest, isoMap) ;
+ Iso.nodeIso(dest, other.dest, isoMap);
}
}
diff --git
a/jena-arq/src/main/java/org/apache/jena/sparql/modify/request/UpdateWriterVisitor.java
b/jena-arq/src/main/java/org/apache/jena/sparql/modify/request/UpdateWriterVisitor.java
index 7a941a1..daa7618 100644
---
a/jena-arq/src/main/java/org/apache/jena/sparql/modify/request/UpdateWriterVisitor.java
+++
b/jena-arq/src/main/java/org/apache/jena/sparql/modify/request/UpdateWriterVisitor.java
@@ -95,7 +95,7 @@ public class UpdateWriterVisitor implements UpdateVisitor {
out.ensureStartOfLine();
out.print("LOAD");
out.print(" ");
- if ( update.getSilent() )
+ if ( update.isSilent() )
out.print("SILENT ");
outputStringAsURI(update.getSource());
@@ -126,7 +126,7 @@ public class UpdateWriterVisitor implements UpdateVisitor {
protected void printUpdate2(UpdateBinaryOp update, String name) {
out.print(name);
- if ( update.getSilent() )
+ if ( update.isSilent() )
out.print(" SILENT");
out.print(" ");
printTargetUpdate2(update.getSrc());
diff --git
a/jena-arq/src/test/java/org/apache/jena/sparql/modify/AbstractTestUpdateGraphMgt.java
b/jena-arq/src/test/java/org/apache/jena/sparql/modify/AbstractTestUpdateGraphMgt.java
index cb4e25d..c2c50f7 100644
---
a/jena-arq/src/test/java/org/apache/jena/sparql/modify/AbstractTestUpdateGraphMgt.java
+++
b/jena-arq/src/test/java/org/apache/jena/sparql/modify/AbstractTestUpdateGraphMgt.java
@@ -43,10 +43,6 @@ public abstract class AbstractTestUpdateGraphMgt extends
AbstractTestUpdateBase
Update u = new UpdateCreate(graphIRI);
UpdateAction.execute(u, gStore);
- // Only true if a graph caching layer exists.
- // JENA-1068 removed that layer
- // (which wasn't safe anyway - it only "existed" in the memory cache)
-// assertTrue(gStore.containsGraph(graphIRI)) ;
assertTrue(graphEmpty(gStore.getGraph(graphIRI)));
// With "auto SILENT" then these aren't errors.
@@ -83,8 +79,6 @@ public abstract class AbstractTestUpdateGraphMgt extends
AbstractTestUpdateBase
u = new UpdateCreate(graphIRI, true);
UpdateAction.execute(u, gStore);
- // JENA-1068
-// assertTrue(gStore.containsGraph(graphIRI)) ;
assertTrue(graphEmpty(gStore.getGraph(graphIRI)));
u = new UpdateDrop(graphIRI);
diff --git
a/jena-arq/src/test/java/org/apache/jena/sparql/modify/TS_Update.java
b/jena-arq/src/test/java/org/apache/jena/sparql/modify/TS_Update.java
index 2d0f7a9..8f4f330 100644
--- a/jena-arq/src/test/java/org/apache/jena/sparql/modify/TS_Update.java
+++ b/jena-arq/src/test/java/org/apache/jena/sparql/modify/TS_Update.java
@@ -25,8 +25,10 @@ import org.junit.runners.Suite.SuiteClasses ;
@RunWith(Suite.class)
@SuiteClasses( {
TestUpdateGraphMem.class
- , TestUpdateGraphMgtMem.class
+ , TestUpdateGraphMgtTxnMem.class
+ , TestUpdateGraphMgtGeneralMem.class
, TestUpdateOperations.class
+ , TestUpdateSilent.class
, TestUpdateCompare.class
, TestUpdateWriter.class
, TestUpdateBuild.class
diff --git
a/jena-arq/src/test/java/org/apache/jena/sparql/modify/TestUpdateGraphMgtMem.java
b/jena-arq/src/test/java/org/apache/jena/sparql/modify/TestUpdateGraphMgtGeneralMem.java
similarity index 93%
copy from
jena-arq/src/test/java/org/apache/jena/sparql/modify/TestUpdateGraphMgtMem.java
copy to
jena-arq/src/test/java/org/apache/jena/sparql/modify/TestUpdateGraphMgtGeneralMem.java
index 1a6bb48..e688a27 100644
---
a/jena-arq/src/test/java/org/apache/jena/sparql/modify/TestUpdateGraphMgtMem.java
+++
b/jena-arq/src/test/java/org/apache/jena/sparql/modify/TestUpdateGraphMgtGeneralMem.java
@@ -21,7 +21,7 @@ package org.apache.jena.sparql.modify ;
import org.apache.jena.sparql.core.DatasetGraph ;
import org.apache.jena.sparql.core.DatasetGraphFactory ;
-public class TestUpdateGraphMgtMem extends AbstractTestUpdateGraphMgt {
+public class TestUpdateGraphMgtGeneralMem extends AbstractTestUpdateGraphMgt {
@Override
protected DatasetGraph getEmptyDatasetGraph() {
return DatasetGraphFactory.create() ;
diff --git
a/jena-arq/src/test/java/org/apache/jena/sparql/modify/TestUpdateGraphMgtMem.java
b/jena-arq/src/test/java/org/apache/jena/sparql/modify/TestUpdateGraphMgtTxnMem.java
similarity index 89%
rename from
jena-arq/src/test/java/org/apache/jena/sparql/modify/TestUpdateGraphMgtMem.java
rename to
jena-arq/src/test/java/org/apache/jena/sparql/modify/TestUpdateGraphMgtTxnMem.java
index 1a6bb48..b27dde3 100644
---
a/jena-arq/src/test/java/org/apache/jena/sparql/modify/TestUpdateGraphMgtMem.java
+++
b/jena-arq/src/test/java/org/apache/jena/sparql/modify/TestUpdateGraphMgtTxnMem.java
@@ -21,9 +21,9 @@ package org.apache.jena.sparql.modify ;
import org.apache.jena.sparql.core.DatasetGraph ;
import org.apache.jena.sparql.core.DatasetGraphFactory ;
-public class TestUpdateGraphMgtMem extends AbstractTestUpdateGraphMgt {
+public class TestUpdateGraphMgtTxnMem extends AbstractTestUpdateGraphMgt {
@Override
protected DatasetGraph getEmptyDatasetGraph() {
- return DatasetGraphFactory.create() ;
+ return DatasetGraphFactory.createTxnMem() ;
}
}
diff --git
a/jena-arq/src/test/java/org/apache/jena/sparql/modify/TestUpdateSilent.java
b/jena-arq/src/test/java/org/apache/jena/sparql/modify/TestUpdateSilent.java
new file mode 100644
index 0000000..c3915c6
--- /dev/null
+++ b/jena-arq/src/test/java/org/apache/jena/sparql/modify/TestUpdateSilent.java
@@ -0,0 +1,148 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.sparql.modify;
+
+import org.apache.jena.sparql.core.DatasetGraph;
+import org.apache.jena.sparql.core.DatasetGraphOne;
+import org.apache.jena.sparql.exec.UpdateExec;
+import org.apache.jena.sparql.graph.GraphFactory;
+import org.apache.jena.update.UpdateException;
+import org.junit.Test;
+
+/**
+ * Tests of SILENT. The tests are written to work aginst {@link
DatasetGraphOne}
+ * which has the characteristic that it does not support named graphs.
+ * <p>
+ * Normally, datasets behave as if all named graphs exists for
adding/copying/moving
+ * into graphs without needing create.
+ * <p>
+ * JENA-2293
+ */
+public class TestUpdateSilent {
+
+ private void test(String updateRequest) {
+ // A characteristic of DatasetGraphOne is that it has no
+ // named graphs and they can't be added.
+ DatasetGraph dataset =
DatasetGraphOne.create(GraphFactory.createGraphMem());
+ UpdateExec.dataset(dataset).update(updateRequest).build().execute();
+ }
+
+ @Test(expected = UpdateException.class)
+ public void LOAD_toNonExistingGraph() {
+ test("LOAD <file:testing/Update/empty.nt> INTO GRAPH
<http://example/no-such-graph>");
+ }
+
+ @Test
+ public void LOAD_SILENT_toNonExistingGraph() {
+ test("LOAD SILENT <file:testing/Update/empty.nt> INTO GRAPH
<http://example/no-such-graph>");
+ }
+
+
+ @Test(expected = UpdateException.class)
+ public void CLEAR_nonExistingGraph() {
+ test("CLEAR GRAPH <http://example/no-such-graph>");
+ }
+
+ @Test
+ public void CLEAR_SILENT_nonExistingGraph() {
+ test("CLEAR SILENT GRAPH <http://example/no-such-graph>");
+ }
+
+ @Test(expected = UpdateException.class)
+ public void CREATE_nonExistingGraph() {
+ //The target is DatasetGraphOne which does not provide named graphs.
+ test("CREATE GRAPH <file:testing/Update/empty.nt>");
+ }
+
+ @Test
+ public void CREATE_SILENT_nonExistingGraph() {
+ test("CREATE SILENT GRAPH <file:testing/Update/empty.nt>");
+ }
+
+ @Test
+ public void DROP_ofNonExistingGraph() {
+ // DROP non-existent is not an error.
+ test("DROP GRAPH <http://example/no-such-graph>");
+ }
+
+ @Test
+ public void DROP_SILENT_ofNonExistingGraph() {
+ test("DROP SILENT GRAPH <http://example/no-such-graph>");
+ }
+
+ @Test(expected = UpdateException.class)
+ public void COPY_toNonExistingGraph() {
+ test("COPY DEFAULT TO <http://example/no-such-graph>");
+ }
+
+ @Test
+ public void COPY_SILENT_toNonExistingGraph() {
+ test("COPY SILENT DEFAULT TO <http://example/no-such-graph>");
+ }
+
+ @Test(expected = UpdateException.class)
+ public void COPY_fromNonExistingGraph() {
+ test("COPY <http://example/no-such-graph> TO DEFAULT");
+ }
+
+ @Test
+ public void COPY_SILENT_fromNonExistingGraph() {
+ test("COPY SILENT <http://example/no-such-graph> TO DEFAULT");
+ }
+
+ @Test(expected = UpdateException.class)
+ public void MOVE_toNonExistingGraph_isError() {
+ test("MOVE DEFAULT TO <http://example/no-such-graph>");
+ }
+
+ @Test
+ public void MOVE_SILENT_toNonExistingGraph() {
+ test("MOVE SILENT DEFAULT TO <http://example/no-such-graph>");
+ }
+
+ @Test(expected = UpdateException.class)
+ public void MOVE_fromNonExistingGraph() {
+ test("MOVE <http://example/no-such-graph> TO DEFAULT");
+ }
+
+ @Test
+ public void MOVE_SILENT_fromNonExistingGraph() {
+ test("MOVE SILENT <http://example/no-such-graph> TO DEFAULT");
+ }
+
+ @Test(expected = UpdateException.class)
+ public void ADD_toNonExistingGraph() {
+ test("ADD DEFAULT TO <http://example/no-such-graph>");
+ }
+
+ @Test
+ public void ADD_SILENT_toNonExistingGraph() {
+ test("ADD SILENT DEFAULT TO <http://example/no-such-graph>");
+ }
+
+ @Test(expected = UpdateException.class)
+ public void ADD_fromNonExistingGraph() {
+ test("ADD <http://example/no-such-graph> TO DEFAULT");
+ }
+
+ @Test
+ public void ADD_SILENT_fromNonExistingGraph() {
+ test("ADD SILENT <http://example/no-such-graph> TO DEFAULT");
+ }
+}
diff --git a/jena-arq/testing/Update/empty.nt b/jena-arq/testing/Update/empty.nt
new file mode 100644
index 0000000..e69de29