JENA-1447: Special case datasets

Project: http://git-wip-us.apache.org/repos/asf/jena/repo
Commit: http://git-wip-us.apache.org/repos/asf/jena/commit/3046d091
Tree: http://git-wip-us.apache.org/repos/asf/jena/tree/3046d091
Diff: http://git-wip-us.apache.org/repos/asf/jena/diff/3046d091

Branch: refs/heads/master
Commit: 3046d0911252dc3f73bc41ef32df9ec3a9aa8232
Parents: f987d61
Author: Andy Seaborne <[email protected]>
Authored: Sun Dec 10 14:21:07 2017 +0000
Committer: Andy Seaborne <[email protected]>
Committed: Sun Dec 10 14:21:07 2017 +0000

----------------------------------------------------------------------
 .../jena/sparql/core/DatasetGraphBase.java      |   5 +
 .../jena/sparql/core/DatasetGraphOne.java       |  59 +++-
 .../jena/sparql/core/DatasetGraphSink.java      | 104 +++++++
 .../jena/sparql/core/DatasetGraphZero.java      | 107 +++++++
 .../jena/sparql/core/TransactionalNull.java     |  55 ++--
 .../apache/jena/sparql/graph/GraphFactory.java  |   1 -
 .../org/apache/jena/sparql/graph/GraphSink.java |  59 ++++
 .../org/apache/jena/sparql/graph/GraphZero.java |  84 ++++++
 .../jena/sparql/graph/PrefixMappingSink.java    |  34 +++
 .../jena/sparql/graph/PrefixMappingZero.java    |  37 +++
 .../sparql/graph/TransactionHandlerNull.java    |  59 ++++
 .../jena/sparql/util/graph/GraphSink.java       |  35 ---
 .../org/apache/jena/sparql/core/TS_Core.java    |   3 +-
 .../jena/sparql/core/TestSpecialGraphNames.java | 218 ++++++++++++++
 .../jena/sparql/core/TestSpecialGraphs.java     | 218 --------------
 .../apache/jena/sparql/core/TestSpecials.java   | 288 +++++++++++++++++++
 16 files changed, 1077 insertions(+), 289 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jena/blob/3046d091/jena-arq/src/main/java/org/apache/jena/sparql/core/DatasetGraphBase.java
----------------------------------------------------------------------
diff --git 
a/jena-arq/src/main/java/org/apache/jena/sparql/core/DatasetGraphBase.java 
b/jena-arq/src/main/java/org/apache/jena/sparql/core/DatasetGraphBase.java
index c553b77..eac9985 100644
--- a/jena-arq/src/main/java/org/apache/jena/sparql/core/DatasetGraphBase.java
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/core/DatasetGraphBase.java
@@ -21,6 +21,7 @@ package org.apache.jena.sparql.core;
 import java.util.Iterator ;
 import org.apache.jena.atlas.io.IndentedLineBuffer ;
 import org.apache.jena.atlas.iterator.Iter ;
+import org.apache.jena.atlas.lib.Lib;
 import org.apache.jena.graph.Graph ;
 import org.apache.jena.graph.Node ;
 import org.apache.jena.shared.Lock ;
@@ -147,6 +148,10 @@ abstract public class DatasetGraphBase implements 
DatasetGraph
         return g == null || g == Node.ANY;
     }
 
+    protected static void unsupportedMethod(Object object, String method) {
+        throw new 
UnsupportedOperationException(Lib.className(object)+"."+method) ;
+    }
+    
     @Override
     public void clear() {
         deleteAny(Node.ANY, Node.ANY, Node.ANY, Node.ANY);

http://git-wip-us.apache.org/repos/asf/jena/blob/3046d091/jena-arq/src/main/java/org/apache/jena/sparql/core/DatasetGraphOne.java
----------------------------------------------------------------------
diff --git 
a/jena-arq/src/main/java/org/apache/jena/sparql/core/DatasetGraphOne.java 
b/jena-arq/src/main/java/org/apache/jena/sparql/core/DatasetGraphOne.java
index 7a420df..8c487be 100644
--- a/jena-arq/src/main/java/org/apache/jena/sparql/core/DatasetGraphOne.java
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/core/DatasetGraphOne.java
@@ -27,27 +27,58 @@ import org.apache.jena.atlas.iterator.NullIterator;
 import org.apache.jena.graph.Graph;
 import org.apache.jena.graph.Node;
 import org.apache.jena.graph.Triple;
-import org.apache.jena.query.ReadWrite ;
-
-/**
- * DatasetGraph of a single graph as default graph. Fixed as one graph (the
- * default) - can not add named graphs.
+import org.apache.jena.query.ReadWrite;
+
+/** DatasetGraph of a single graph as default graph.
+ * <p>
+ *  Fixed as one graph (the default) - can not add named graphs.
+ *  <p>
+ *  Passes transactions down to a nominated backing {@link DatasetGraph}
+ *  
  */
 public class DatasetGraphOne extends DatasetGraphBaseFind {
     private final Graph graph;
+    private final DatasetGraph backingDGS;
+    private final Transactional txn;
+    private final boolean supportsAbort;
 
+    public DatasetGraphOne(Graph graph, DatasetGraph backing) {
+        this.graph = graph;
+        backingDGS = backing;
+        supportsAbort = backing.supportsTransactionAbort();
+        txn = backing;
+    }
+    
     public DatasetGraphOne(Graph graph) {
         this.graph = graph;
+        if ( graph instanceof GraphView ) {
+            backingDGS = ((GraphView)graph).getDataset();
+            txn = backingDGS;
+            supportsAbort = backingDGS.supportsTransactionAbort();
+        } else {
+            txn = TransactionalLock.createMRSW();
+            backingDGS = null;
+            supportsAbort = false;
+        }
+    }
+    
+    public DatasetGraphOne(Graph graph, Transactional transactional) {
+        this.graph = graph;
+        backingDGS = null;
+        if ( transactional == null )
+            txn = TransactionalLock.createMRSW();
+        else
+            txn = transactional;
+        supportsAbort = false; 
     }
     
-    private final Transactional txn                     = 
TransactionalLock.createMRSW() ;
     @Override public void begin(ReadWrite mode)         { txn.begin(mode) ; }
     @Override public void commit()                      { txn.commit() ; }
     @Override public void abort()                       { txn.abort() ; }
     @Override public boolean isInTransaction()          { return 
txn.isInTransaction() ; }
     @Override public void end()                         { txn.end(); }
     @Override public boolean supportsTransactions()     { return true ; }
-    @Override public boolean supportsTransactionAbort() { return false ; }
+    @Override public boolean supportsTransactionAbort() { return supportsAbort 
; }
 
     @Override
     public boolean containsGraph(Node graphNode) {
@@ -83,7 +114,7 @@ public class DatasetGraphOne extends DatasetGraphBaseFind {
         if ( Quad.isDefaultGraph(g) )
             graph.add(new Triple(s, p, o));
         else
-            throw new UnsupportedOperationException("DatasetGraphOne.add/named 
graph");
+            unsupportedMethod(this, "add(named graph)");
     }
 
     @Override
@@ -91,7 +122,7 @@ public class DatasetGraphOne extends DatasetGraphBaseFind {
         if ( isDefaultGraph(quad) )
             graph.add(quad.asTriple());
         else
-            throw new UnsupportedOperationException("DatasetGraphOne.add/named 
graph");
+            unsupportedMethod(this, "add(named graph)");
     }
 
     @Override
@@ -99,7 +130,7 @@ public class DatasetGraphOne extends DatasetGraphBaseFind {
         if ( Quad.isDefaultGraph(g) )
             graph.delete(new Triple(s, p, o));
         else
-            throw new 
UnsupportedOperationException("DatasetGraphOne.delete/named graph");
+            unsupportedMethod(this, "delete(named graph)");
     }
 
     @Override
@@ -107,22 +138,22 @@ public class DatasetGraphOne extends DatasetGraphBaseFind 
{
         if ( isDefaultGraph(quad) )
             graph.delete(quad.asTriple());
         else
-            throw new 
UnsupportedOperationException("DatasetGraphOne.delete/named graph");
+            unsupportedMethod(this, "delete(named graph)");
     }
 
     @Override
     public void setDefaultGraph(Graph g) {
-        throw new 
UnsupportedOperationException("DatasetGraphOne.setDefaultGraph");
+        unsupportedMethod(this, "setDefaultGraph");
     }
 
     @Override
     public void addGraph(Node graphName, Graph graph) {
-        throw new UnsupportedOperationException("DatasetGraphOne.addGraph");
+        unsupportedMethod(this, "addGraph");
     }
 
     @Override
     public void removeGraph(Node graphName) {
-        throw new UnsupportedOperationException("DatasetGraphOne.removeGraph");
+        unsupportedMethod(this, "removeGraph");
     }
 
     // -- Not needed -- implement find(g,s,p,o) directly.

http://git-wip-us.apache.org/repos/asf/jena/blob/3046d091/jena-arq/src/main/java/org/apache/jena/sparql/core/DatasetGraphSink.java
----------------------------------------------------------------------
diff --git 
a/jena-arq/src/main/java/org/apache/jena/sparql/core/DatasetGraphSink.java 
b/jena-arq/src/main/java/org/apache/jena/sparql/core/DatasetGraphSink.java
new file mode 100644
index 0000000..64735d0
--- /dev/null
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/core/DatasetGraphSink.java
@@ -0,0 +1,104 @@
+/*
+ * 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.core;
+
+import java.util.Iterator;
+
+import org.apache.jena.atlas.iterator.Iter;
+import org.apache.jena.graph.Graph;
+import org.apache.jena.graph.Node;
+import org.apache.jena.query.ReadWrite;
+import org.apache.jena.sparql.graph.GraphSink;
+
+
+/** 
+ * An always empty {@link DatasetGraph} that accepts changes but ignores them.
+ * 
+ * @see DatasetGraphZero
+ */
+public class DatasetGraphSink extends DatasetGraphBaseFind {
+
+    public static DatasetGraph create() { return new DatasetGraphSink(); }
+    
+    private Graph dftGraph = GraphSink.instance();
+    
+    public DatasetGraphSink() {}
+    
+    private TransactionalNull txn                       = 
TransactionalNull.create();
+    @Override public void begin(ReadWrite mode)         { txn.begin(mode); }
+    @Override public void commit()                      { txn.commit(); }
+    @Override public void abort()                       { txn.abort(); }
+    @Override public boolean isInTransaction()          { return 
txn.isInTransaction(); }
+    @Override public void end()                         { txn.end(); }
+    @Override public boolean supportsTransactions()     { return true; }
+    // Because there are never any changes, abort() means "finish".  
+    @Override public boolean supportsTransactionAbort() { return true; }
+    
+    @Override
+    public Iterator<Node> listGraphNodes() {
+        return Iter.nullIterator();
+    }
+    
+    @Override
+    protected Iterator<Quad> findInDftGraph(Node s, Node p, Node o) {
+        return Iter.nullIterator();
+    }
+    
+    @Override
+    protected Iterator<Quad> findInSpecificNamedGraph(Node g, Node s, Node p, 
Node o) {
+        return Iter.nullIterator();
+    }
+    
+    @Override
+    protected Iterator<Quad> findInAnyNamedGraphs(Node s, Node p, Node o) {
+        return Iter.nullIterator();
+    }
+    
+    @Override
+    public Graph getDefaultGraph() {
+        return dftGraph;
+    }
+    @Override
+    public Graph getGraph(Node graphNode) {
+        return null;
+    }
+    @Override
+    public void add(Quad quad) { /* ignore */ } 
+    
+    @Override
+    public void delete(Quad quad) { /* ignore */ }
+    
+    @Override
+    public void deleteAny(Node g, Node s, Node p, Node o) { /* ignore */ }
+    
+    @Override
+    public void setDefaultGraph(Graph g) { /* ignore */ }
+
+    @Override
+    public void addGraph(Node graphName, Graph graph) { /* ignore */ }
+
+    @Override
+    public void removeGraph(Node graphName) { /* ignore */ }
+    
+    @Override
+    public void close() {
+        txn.remove();
+        txn = null;
+    }
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/3046d091/jena-arq/src/main/java/org/apache/jena/sparql/core/DatasetGraphZero.java
----------------------------------------------------------------------
diff --git 
a/jena-arq/src/main/java/org/apache/jena/sparql/core/DatasetGraphZero.java 
b/jena-arq/src/main/java/org/apache/jena/sparql/core/DatasetGraphZero.java
new file mode 100644
index 0000000..a5a813b
--- /dev/null
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/core/DatasetGraphZero.java
@@ -0,0 +1,107 @@
+/*
+ * 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.core;
+
+import java.util.Iterator;
+
+import org.apache.jena.atlas.iterator.Iter;
+import org.apache.jena.graph.Graph;
+import org.apache.jena.graph.Node;
+import org.apache.jena.query.ReadWrite;
+import org.apache.jena.sparql.graph.GraphZero;
+
+/** An always empty {@link DatasetGraph}. 
+ * One graph (the default graph) with zero triples.
+ * No changes allowed - this is not a sink.
+ * @see DatasetGraphSink
+ */
+public class DatasetGraphZero extends DatasetGraphBaseFind {
+
+    public static DatasetGraph create() { return new DatasetGraphZero(); }
+    
+    private Graph dftGraph = GraphZero.instance();
+
+    public DatasetGraphZero() {}
+    
+    private TransactionalNull txn                       = 
TransactionalNull.create();
+    @Override public void begin(ReadWrite mode)         { txn.begin(mode); }
+    @Override public void commit()                      { txn.commit(); }
+    @Override public void abort()                       { txn.abort(); }
+    @Override public boolean isInTransaction()          { return 
txn.isInTransaction(); }
+    @Override public void end()                         { txn.end(); }
+    @Override public boolean supportsTransactions()     { return true; }
+    // Because there are never any changes, abort() means "finish".  
+    @Override public boolean supportsTransactionAbort() { return true; }
+    
+    @Override
+    public Iterator<Node> listGraphNodes() {
+        return Iter.nullIterator();
+    }
+    
+    @Override
+    protected Iterator<Quad> findInDftGraph(Node s, Node p, Node o) {
+        return Iter.nullIterator();
+    }
+    
+    @Override
+    protected Iterator<Quad> findInSpecificNamedGraph(Node g, Node s, Node p, 
Node o) {
+        return Iter.nullIterator();
+    }
+    
+    @Override
+    protected Iterator<Quad> findInAnyNamedGraphs(Node s, Node p, Node o) {
+        return Iter.nullIterator();
+    }
+    
+    @Override
+    public Graph getDefaultGraph() {
+        return dftGraph;
+    }
+    
+    @Override
+    public Graph getGraph(Node graphNode) {
+        return null;
+    }
+    
+    @Override
+    public void add(Quad quad) { unsupportedMethod(this, "add") ; } 
+    
+    @Override
+    public void delete(Quad quad) { unsupportedMethod(this, "delete") ; }
+    
+    @Override
+    public void deleteAny(Node g, Node s, Node p, Node o) {
+        throw new UnsupportedOperationException("deleteAny");
+    }
+
+    @Override
+    public void setDefaultGraph(Graph g) {
+        throw new UnsupportedOperationException("setDefaultGraph");
+    }
+
+    @Override
+    public void addGraph(Node graphName, Graph graph) {
+        throw new UnsupportedOperationException("addGraph");
+    }
+
+    @Override
+    public void removeGraph(Node graphName) {
+        throw new UnsupportedOperationException("removeGraph");
+    }
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/3046d091/jena-arq/src/main/java/org/apache/jena/sparql/core/TransactionalNull.java
----------------------------------------------------------------------
diff --git 
a/jena-arq/src/main/java/org/apache/jena/sparql/core/TransactionalNull.java 
b/jena-arq/src/main/java/org/apache/jena/sparql/core/TransactionalNull.java
index 17a6019..618ad38 100644
--- a/jena-arq/src/main/java/org/apache/jena/sparql/core/TransactionalNull.java
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/core/TransactionalNull.java
@@ -18,41 +18,56 @@
 
 package org.apache.jena.sparql.core;
 
-import org.apache.jena.query.ReadWrite ;
+import org.apache.jena.query.ReadWrite;
+import org.apache.jena.sparql.JenaTransactionException;
 
-public class TransactionalNull implements Transactional
-{
-    boolean inTransaction = false ;
+/**
+ * A null action {@link Transactional}.
+ * Does not protect anything but does track the transaction status.
+ * It does provide "abort".   
+ */
+public class TransactionalNull implements Transactional {
+    public static TransactionalNull create() { return new TransactionalNull(); 
}
     
+    private ThreadLocal<Boolean> inTransaction = ThreadLocal.withInitial(() -> 
Boolean.FALSE);
+
     @Override
-    public void begin(ReadWrite readWrite)
-    {
-        inTransaction = true ;
+    public void begin(ReadWrite readWrite) {
+        if ( inTransaction.get() )
+            throw new JenaTransactionException("Already in transaction"); 
+        inTransaction.set(true);
     }
 
     @Override
-    public void commit()
-    {
-        inTransaction = false ;
+    public void commit() {
+        if ( ! inTransaction.get() )
+            throw new JenaTransactionException("Not in transaction"); 
+        inTransaction.set(false);
     }
 
     @Override
-    public void abort()
-    {
-        inTransaction = false ;
+    public void abort() {
+        if ( ! inTransaction.get() )
+            throw new JenaTransactionException("Not in transaction"); 
+        inTransaction.set(false);
     }
 
     @Override
-    public boolean isInTransaction()
-    {
-        return inTransaction ;
+    public boolean isInTransaction() {
+        return inTransaction.get();
     }
 
     @Override
-    public void end()
-    {
-        inTransaction = false ;
+    public void end() {
+        inTransaction.set(false);
     }
 
-}
+//    @Override
+//    public boolean promote() {
+//        return true;
+//    }
 
+    public void remove() {
+        inTransaction.remove();
+    }
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/3046d091/jena-arq/src/main/java/org/apache/jena/sparql/graph/GraphFactory.java
----------------------------------------------------------------------
diff --git 
a/jena-arq/src/main/java/org/apache/jena/sparql/graph/GraphFactory.java 
b/jena-arq/src/main/java/org/apache/jena/sparql/graph/GraphFactory.java
index f07996c..fe0c12c 100644
--- a/jena-arq/src/main/java/org/apache/jena/sparql/graph/GraphFactory.java
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/graph/GraphFactory.java
@@ -26,7 +26,6 @@ import org.apache.jena.graph.impl.GraphPlain ;
 import org.apache.jena.rdf.model.Model ;
 import org.apache.jena.rdf.model.ModelFactory ;
 import org.apache.jena.sparql.SystemARQ ;
-import org.apache.jena.sparql.util.graph.GraphSink ;
 import org.apache.jena.system.JenaSystem ;
 
 /** Ways to make graphs and models */

http://git-wip-us.apache.org/repos/asf/jena/blob/3046d091/jena-arq/src/main/java/org/apache/jena/sparql/graph/GraphSink.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/graph/GraphSink.java 
b/jena-arq/src/main/java/org/apache/jena/sparql/graph/GraphSink.java
new file mode 100644
index 0000000..ada3862
--- /dev/null
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/graph/GraphSink.java
@@ -0,0 +1,59 @@
+/*
+ * 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.graph;
+
+import org.apache.jena.graph.Graph;
+import org.apache.jena.graph.TransactionHandler;
+import org.apache.jena.graph.Triple ;
+import org.apache.jena.graph.impl.GraphBase ;
+import org.apache.jena.shared.PrefixMapping;
+import org.apache.jena.util.iterator.ExtendedIterator ;
+import org.apache.jena.util.iterator.NullIterator ;
+
+/** 
+ * Black hole graph - adds and deletes are silently ignored.
+ * @see GraphZero
+ */
+public class GraphSink extends GraphBase
+{
+    private static Graph graph = new GraphSink();
+    public static Graph instance() {
+        return graph;
+    }
+    
+    @Override
+    protected ExtendedIterator<Triple> graphBaseFind(Triple triple)
+    { return NullIterator.instance() ; }
+    
+    @Override
+    public void performAdd( Triple t ) {}
+    
+    @Override
+    public void performDelete( Triple t ) {}
+    
+    @Override
+    protected PrefixMapping createPrefixMapping() { 
+        return new PrefixMappingSink() ;
+    }
+    
+    @Override 
+    public TransactionHandler getTransactionHandler() {
+        return new TransactionHandlerNull(); 
+    }
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/3046d091/jena-arq/src/main/java/org/apache/jena/sparql/graph/GraphZero.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/graph/GraphZero.java 
b/jena-arq/src/main/java/org/apache/jena/sparql/graph/GraphZero.java
new file mode 100644
index 0000000..aba5cac
--- /dev/null
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/graph/GraphZero.java
@@ -0,0 +1,84 @@
+/*
+ * 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.graph;
+
+import org.apache.jena.graph.Capabilities;
+import org.apache.jena.graph.Graph;
+import org.apache.jena.graph.TransactionHandler;
+import org.apache.jena.graph.Triple;
+import org.apache.jena.graph.impl.AllCapabilities;
+import org.apache.jena.graph.impl.GraphBase;
+import org.apache.jena.shared.PrefixMapping;
+import org.apache.jena.util.iterator.ExtendedIterator;
+import org.apache.jena.util.iterator.NullIterator;
+
+/** Immutable empty graph.  
+ *  @see GraphSink
+ */
+public class GraphZero extends GraphBase {
+    
+    private static Graph graph = new GraphZero();
+    public static Graph instance() {
+        return graph;
+    }
+
+    private GraphZero() {}
+    
+    @Override
+    protected ExtendedIterator<Triple> graphBaseFind(Triple triplePattern) {
+        return NullIterator.instance();
+    }
+    
+    
+    @Override 
+    public TransactionHandler getTransactionHandler() {
+        return new TransactionHandlerNull(); 
+    }
+    
+    @Override
+    protected PrefixMapping createPrefixMapping() { 
+        return new PrefixMappingZero() ;
+    }
+    
+    // Choice point: AddDeniedException/DeleteDeniedException or 
UnsupportedOperationException.
+    //
+    // AddDeniedException is more access centric, e.g. permissions, 
+    // and may be different for different callers.
+    //
+    // UnsupportedOperationException is the general java "no" for not 
available ata ll,
+    // but is different from the Jena core exceptions.
+    @Override
+    public void performAdd( Triple t ) { throw new 
UnsupportedOperationException("add triple"); }
+    
+    @Override
+    public void performDelete( Triple t ) { throw new 
UnsupportedOperationException("delete triple"); }
+
+    @Override
+    public Capabilities getCapabilities() {
+        if ( capabilities == null ) {
+            capabilities = new AllCapabilities() {
+                @Override public boolean addAllowed() { return false; }
+                @Override public boolean addAllowed( boolean every ) { return 
false; } 
+                @Override public boolean deleteAllowed() { return false; }
+                @Override public boolean deleteAllowed( boolean every ) { 
return false; } 
+            };
+        }
+        return capabilities;
+    }
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/3046d091/jena-arq/src/main/java/org/apache/jena/sparql/graph/PrefixMappingSink.java
----------------------------------------------------------------------
diff --git 
a/jena-arq/src/main/java/org/apache/jena/sparql/graph/PrefixMappingSink.java 
b/jena-arq/src/main/java/org/apache/jena/sparql/graph/PrefixMappingSink.java
new file mode 100644
index 0000000..5a5ed02
--- /dev/null
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/graph/PrefixMappingSink.java
@@ -0,0 +1,34 @@
+/*
+ * 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.graph;
+
+import org.apache.jena.shared.impl.PrefixMappingImpl;
+
+/** Sink PrefixMapping. Accepts chnages but does not retain state. */ 
+public class PrefixMappingSink extends PrefixMappingImpl {
+    @Override
+    protected void set(String prefix, String uri) { }
+
+    @Override
+    protected String get(String prefix) { return null; }
+
+    @Override
+    protected void remove(String prefix) { }
+    
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jena/blob/3046d091/jena-arq/src/main/java/org/apache/jena/sparql/graph/PrefixMappingZero.java
----------------------------------------------------------------------
diff --git 
a/jena-arq/src/main/java/org/apache/jena/sparql/graph/PrefixMappingZero.java 
b/jena-arq/src/main/java/org/apache/jena/sparql/graph/PrefixMappingZero.java
new file mode 100644
index 0000000..9c2a7aa
--- /dev/null
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/graph/PrefixMappingZero.java
@@ -0,0 +1,37 @@
+/*
+ * 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.graph;
+
+import org.apache.jena.shared.impl.PrefixMappingImpl;
+
+/** Immutable empty PrefixMapping. */
+public class PrefixMappingZero extends PrefixMappingImpl {
+    @Override
+    protected void set(String prefix, String uri) {
+        throw new UnsupportedOperationException("set prefix");
+    }
+
+    @Override
+    protected String get(String prefix) { return null; }
+
+    @Override
+    protected void remove(String prefix) { 
+        throw new UnsupportedOperationException("remove prefix");
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jena/blob/3046d091/jena-arq/src/main/java/org/apache/jena/sparql/graph/TransactionHandlerNull.java
----------------------------------------------------------------------
diff --git 
a/jena-arq/src/main/java/org/apache/jena/sparql/graph/TransactionHandlerNull.java
 
b/jena-arq/src/main/java/org/apache/jena/sparql/graph/TransactionHandlerNull.java
new file mode 100644
index 0000000..8245695
--- /dev/null
+++ 
b/jena-arq/src/main/java/org/apache/jena/sparql/graph/TransactionHandlerNull.java
@@ -0,0 +1,59 @@
+/*
+ * 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.graph;
+
+import org.apache.jena.graph.TransactionHandler;
+import org.apache.jena.graph.impl.TransactionHandlerBase;
+import org.apache.jena.sparql.JenaTransactionException;
+
+/** Implementation of {@link TransactionHandler} that does nothing but track 
the transction state. */
+public class TransactionHandlerNull extends TransactionHandlerBase {
+ 
+    private ThreadLocal<Boolean> inTransaction = 
ThreadLocal.withInitial(()->Boolean.FALSE);
+    
+    @Override
+    public boolean transactionsSupported() {
+        return true;
+    }
+    
+    @Override
+    public void begin() {
+        if ( inTransaction.get() )
+            throw new JenaTransactionException("Already in transaction"); 
+        inTransaction.set(true);
+    }
+
+    @Override
+    public void commit() {
+        if ( ! inTransaction.get() )
+            throw new JenaTransactionException("Not in transaction"); 
+        inTransaction.set(false);
+    }
+
+    @Override
+    public void abort() {
+        if ( ! inTransaction.get() )
+            throw new JenaTransactionException("Not in transaction"); 
+        inTransaction.set(false);
+    }
+
+    public void remove() {
+        inTransaction.remove();
+    }
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/3046d091/jena-arq/src/main/java/org/apache/jena/sparql/util/graph/GraphSink.java
----------------------------------------------------------------------
diff --git 
a/jena-arq/src/main/java/org/apache/jena/sparql/util/graph/GraphSink.java 
b/jena-arq/src/main/java/org/apache/jena/sparql/util/graph/GraphSink.java
deleted file mode 100644
index fff86bd..0000000
--- a/jena-arq/src/main/java/org/apache/jena/sparql/util/graph/GraphSink.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * 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.util.graph;
-
-import org.apache.jena.graph.Triple ;
-import org.apache.jena.graph.impl.GraphBase ;
-import org.apache.jena.util.iterator.ExtendedIterator ;
-import org.apache.jena.util.iterator.NullIterator ;
-
-/** Black hole for triples */
-public class GraphSink extends GraphBase
-{
-    @Override
-    protected ExtendedIterator<Triple> graphBaseFind(Triple triple)
-    { return NullIterator.instance() ; }
-    
-    @Override
-    public void performAdd( Triple t ) {}
-}

http://git-wip-us.apache.org/repos/asf/jena/blob/3046d091/jena-arq/src/test/java/org/apache/jena/sparql/core/TS_Core.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/test/java/org/apache/jena/sparql/core/TS_Core.java 
b/jena-arq/src/test/java/org/apache/jena/sparql/core/TS_Core.java
index aba43cf..c851ee8 100644
--- a/jena-arq/src/test/java/org/apache/jena/sparql/core/TS_Core.java
+++ b/jena-arq/src/test/java/org/apache/jena/sparql/core/TS_Core.java
@@ -42,7 +42,8 @@ import org.junit.runners.Suite ;
     , TestDatasetGraphBaseFindPattern_General.class
     , TestDatasetGraphBaseFindPattern_Mem.class
     
-    , TestSpecialGraphs.class
+    , TestSpecialGraphNames.class
+    , TestSpecials.class
 })
 
 public class TS_Core

http://git-wip-us.apache.org/repos/asf/jena/blob/3046d091/jena-arq/src/test/java/org/apache/jena/sparql/core/TestSpecialGraphNames.java
----------------------------------------------------------------------
diff --git 
a/jena-arq/src/test/java/org/apache/jena/sparql/core/TestSpecialGraphNames.java 
b/jena-arq/src/test/java/org/apache/jena/sparql/core/TestSpecialGraphNames.java
new file mode 100644
index 0000000..364fa54
--- /dev/null
+++ 
b/jena-arq/src/test/java/org/apache/jena/sparql/core/TestSpecialGraphNames.java
@@ -0,0 +1,218 @@
+/**
+ * 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.core;
+
+import static org.apache.jena.sparql.core.TestSpecialGraphNames.Mode.QUADS ;
+import static org.apache.jena.sparql.core.TestSpecialGraphNames.Mode.TRIPLES ;
+import static org.junit.Assert.assertEquals ;
+
+import java.util.Arrays ;
+import java.util.Collection ;
+import java.util.List ;
+
+import org.apache.jena.atlas.iterator.Iter ;
+import org.apache.jena.atlas.lib.Creator ;
+import org.apache.jena.atlas.lib.StrUtils ;
+import org.apache.jena.sparql.algebra.Algebra ;
+import org.apache.jena.sparql.algebra.Op ;
+import org.apache.jena.sparql.core.DatasetGraph ;
+import org.apache.jena.sparql.core.DatasetGraphFactory ;
+import org.apache.jena.sparql.core.Quad ;
+import org.apache.jena.sparql.engine.QueryIterator ;
+import org.apache.jena.sparql.engine.binding.Binding ;
+import org.apache.jena.sparql.sse.SSE ;
+import org.apache.jena.sparql.sse.builders.BuilderGraph ;
+import org.junit.Test ;
+import org.junit.runner.RunWith ;
+import org.junit.runners.Parameterized ;
+import org.junit.runners.Parameterized.Parameters ;
+
+/** Test special graph names. */
+@RunWith(Parameterized.class)
+public class TestSpecialGraphNames {
+    @Parameters(name = "{index}: {0}")
+    public static Collection<Object[]> data() {
+        Creator<DatasetGraph> datasetGeneralMaker = ()-> 
DatasetGraphFactory.createGeneral() ; 
+        Creator<DatasetGraph> datasetTxnMemMaker  = ()-> 
DatasetGraphFactory.createTxnMem() ;
+        Creator<DatasetGraph> datasetMemMaker     = ()-> 
DatasetGraphFactory.create() ;
+        return Arrays.asList(new Object[][] {
+            { "General",  datasetGeneralMaker },
+            { "Plain",    datasetMemMaker} ,
+            { "TxnMem",   datasetTxnMemMaker}
+            });
+    }
+    
+    static enum Mode { TRIPLES, QUADS } 
+    
+    static String x1 = StrUtils.strjoinNL("(dataset",
+                                          "  (graph (<s> <p> <x>) (<x> <p> 
<o>) (<x2> <p> <o1>) (<x2> <p> <o3>) (<x2> <p> <o4>))",
+                                          "  (graph <g1> (<s1> <p1> <s1>) 
(<s1> <p1> <s2>))",
+                                          "  (graph <g2> (triple <s2> <p2> 
<o2>) (triple <s2> <p3> <o3>))",
+                                          "  (graph <g3> (triple <s2> <p2> 
<o2>))", // Duplicate triple
+                                          ")") ;
+    private DatasetGraph dsg ;
+    
+    public TestSpecialGraphNames(String label, Creator<DatasetGraph> maker) {
+        this.dsg = BuilderGraph.buildDataset(maker.create(), SSE.parse(x1)) ;
+    }
+
+    @Test
+    public void union_dft_1t() {
+        union_dft_1(TRIPLES) ;
+    }
+    
+    @Test
+    public void union_dft_1q() {
+        union_dft_1(QUADS) ;
+    }
+    
+    private void union_dft_1(Mode mode) {
+        Op op = op("(bgp (?s ?p ?o))", mode) ;
+        List<Binding> results = exec(op) ;
+        assertEquals(5, results.size()) ;
+        Op op2 = Algebra.unionDefaultGraph(op) ;
+        List<Binding> results2 = exec(op2) ;
+        assertEquals(4, results2.size()) ;
+    }
+    
+    @Test
+    public void graph_union_1t() {
+        List<Binding> results = exec("(graph <" + Quad.unionGraph.getURI() + 
"> (bgp (<s2> ?p ?o)))", TRIPLES) ;
+        assertEquals(2, results.size()) ;
+    }
+
+    @Test
+    public void graph_union_1q() {
+        List<Binding> results = exec("(graph <" + Quad.unionGraph.getURI() + 
"> (bgp (<s2> ?p ?o)))", QUADS) ;
+        assertEquals(2, results.size()) ;
+    }
+
+    @Test
+    public void graph_union_2t() {
+        List<Binding> results = exec("(graph <" + Quad.unionGraph.getURI() + 
"> (bgp (<s1> ?p ?o) (?o ?q ?z)  ))", TRIPLES) ;
+        assertEquals(4, results.size()) ;
+    }
+
+    @Test
+    public void graph_union_2q() {
+        List<Binding> results = exec("(graph <" + Quad.unionGraph.getURI() + 
"> (bgp (<s1> ?p ?o) (?o ?q ?z)  ))", QUADS) ;
+        assertEquals(4, results.size()) ;
+    }
+
+    @Test
+    public void graph_dft_1t() {
+        List<Binding> results = exec("(graph <" + 
Quad.defaultGraphIRI.getURI() + "> (bgp (<s2> ?p ?o)))", TRIPLES) ;
+        assertEquals(0, results.size()) ;
+    }
+
+    @Test
+    public void graph_dft_1q() {
+        List<Binding> results = exec("(graph <" + 
Quad.defaultGraphIRI.getURI() + "> (bgp (<s2> ?p ?o)))", QUADS) ;
+        assertEquals(0, results.size()) ;
+    }
+
+    @Test
+    public void graph_dft_2t() {
+        List<Binding> results = exec("(graph <" + 
Quad.defaultGraphIRI.getURI() + "> (bgp (<s> ?p ?o)))", TRIPLES) ;
+        assertEquals(1, results.size()) ;
+    }
+
+    @Test
+    public void graph_dft_2q() {
+        List<Binding> results = exec("(graph <" + 
Quad.defaultGraphIRI.getURI() + "> (bgp (<s> ?p ?o)))", QUADS) ;
+        assertEquals(1, results.size()) ;
+    }
+
+    @Test
+    public void graph_dft_3t() {
+        List<Binding> results = exec("(graph <" + 
Quad.defaultGraphIRI.getURI() + "> (bgp (?x ?p ?z) (?z ?q ?y) ))", TRIPLES) ;
+        assertEquals(1, results.size()) ;
+    }
+
+    @Test
+    public void graph_dft_3q() {
+        List<Binding> results = exec("(graph <" + 
Quad.defaultGraphIRI.getURI() + "> (bgp (?x ?p ?z) (?z ?q ?y) ))", QUADS) ;
+        assertEquals(1, results.size()) ;
+    }
+
+    @Test
+    public void graph_dftg_1t() {
+        List<Binding> results = exec("(graph <" + 
Quad.defaultGraphNodeGenerated.getURI() + "> (bgp (<s2> ?p ?o)))", TRIPLES) ;
+        assertEquals(0, results.size()) ;
+    }
+    
+    @Test
+    public void graph_dftg_2t() {
+        List<Binding> results = exec("(graph <" + 
Quad.defaultGraphNodeGenerated.getURI() + "> (bgp (<x2> ?p ?o)))", TRIPLES) ;
+        assertEquals(3, results.size()) ;
+    }
+    
+    @Test
+    public void graph_dftg_1q() {
+        List<Binding> results = exec("(graph <" + 
Quad.defaultGraphNodeGenerated.getURI() + "> (bgp (<s2> ?p ?o)))", QUADS) ;
+        assertEquals(0, results.size()) ;
+    }
+
+    @Test
+    public void graph_dftg_2q() {
+        List<Binding> results = exec("(graph <" + 
Quad.defaultGraphNodeGenerated.getURI() + "> (bgp (<x2> ?p ?o)))", QUADS) ;
+        assertEquals(3, results.size()) ;
+    }
+
+    @Test
+    public void direct_3t() {
+        List<Binding> results = exec("(graph <g1> (bgp (<s1> ?p ?o)))", 
TRIPLES) ;
+        assertEquals(2, results.size()) ;
+    }
+
+    @Test
+    public void direct_3q() {
+        List<Binding> results = exec("(graph <g1> (bgp (<s1> ?p ?o)))", QUADS) 
;
+        assertEquals(2, results.size()) ;
+    }
+
+    @Test
+    public void direct_4() {
+        List<Binding> results = exec("(graph <g1> (bgp (<s2> ?p ?o)))", 
TRIPLES) ;
+        assertEquals(0, results.size()) ;
+    }
+
+    @Test
+    public void direct_5() {
+        List<Binding> results = exec("(graph <g2> (bgp (<s2> ?p ?o)))", 
TRIPLES) ;
+        assertEquals(2, results.size()) ;
+    }
+
+    private List<Binding> exec(String string, Mode mode) {
+        Op op = op(string, mode) ;
+        return exec(op) ;
+    }
+    
+    private List<Binding> exec(Op op) {
+        QueryIterator qIter = Algebra.exec(op, dsg) ;
+        return Iter.toList(qIter) ;
+    }
+
+    protected Op op(String pattern, Mode mode) {
+        Op op = SSE.parseOp(pattern) ;
+        if ( mode == Mode.QUADS )
+            op = Algebra.toQuadForm(op) ;
+        return op ;
+    }
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/3046d091/jena-arq/src/test/java/org/apache/jena/sparql/core/TestSpecialGraphs.java
----------------------------------------------------------------------
diff --git 
a/jena-arq/src/test/java/org/apache/jena/sparql/core/TestSpecialGraphs.java 
b/jena-arq/src/test/java/org/apache/jena/sparql/core/TestSpecialGraphs.java
deleted file mode 100644
index 613994f..0000000
--- a/jena-arq/src/test/java/org/apache/jena/sparql/core/TestSpecialGraphs.java
+++ /dev/null
@@ -1,218 +0,0 @@
-/**
- * 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.core;
-
-import static org.apache.jena.sparql.core.TestSpecialGraphs.Mode.QUADS ;
-import static org.apache.jena.sparql.core.TestSpecialGraphs.Mode.TRIPLES ;
-import static org.junit.Assert.assertEquals ;
-
-import java.util.Arrays ;
-import java.util.Collection ;
-import java.util.List ;
-
-import org.apache.jena.atlas.iterator.Iter ;
-import org.apache.jena.atlas.lib.Creator ;
-import org.apache.jena.atlas.lib.StrUtils ;
-import org.apache.jena.sparql.algebra.Algebra ;
-import org.apache.jena.sparql.algebra.Op ;
-import org.apache.jena.sparql.core.DatasetGraph ;
-import org.apache.jena.sparql.core.DatasetGraphFactory ;
-import org.apache.jena.sparql.core.Quad ;
-import org.apache.jena.sparql.engine.QueryIterator ;
-import org.apache.jena.sparql.engine.binding.Binding ;
-import org.apache.jena.sparql.sse.SSE ;
-import org.apache.jena.sparql.sse.builders.BuilderGraph ;
-import org.junit.Test ;
-import org.junit.runner.RunWith ;
-import org.junit.runners.Parameterized ;
-import org.junit.runners.Parameterized.Parameters ;
-
-/** Test special graphs */
-@RunWith(Parameterized.class)
-public class TestSpecialGraphs {
-    @Parameters(name = "{index}: {0}")
-    public static Collection<Object[]> data() {
-        Creator<DatasetGraph> datasetGeneralMaker = ()-> 
DatasetGraphFactory.createGeneral() ; 
-        Creator<DatasetGraph> datasetTxnMemMaker  = ()-> 
DatasetGraphFactory.createTxnMem() ;
-        Creator<DatasetGraph> datasetMemMaker     = ()-> 
DatasetGraphFactory.create() ;
-        return Arrays.asList(new Object[][] {
-            { "General",  datasetGeneralMaker },
-            { "Plain",    datasetMemMaker} ,
-            { "TxnMem",   datasetTxnMemMaker}
-            });
-    }
-    
-    static enum Mode { TRIPLES, QUADS } 
-    
-    static String x1 = StrUtils.strjoinNL("(dataset",
-                                          "  (graph (<s> <p> <x>) (<x> <p> 
<o>) (<x2> <p> <o1>) (<x2> <p> <o3>) (<x2> <p> <o4>))",
-                                          "  (graph <g1> (<s1> <p1> <s1>) 
(<s1> <p1> <s2>))",
-                                          "  (graph <g2> (triple <s2> <p2> 
<o2>) (triple <s2> <p3> <o3>))",
-                                          "  (graph <g3> (triple <s2> <p2> 
<o2>))", // Duplicate triple
-                                          ")") ;
-    private DatasetGraph dsg ;
-    
-    public TestSpecialGraphs(String label, Creator<DatasetGraph> maker) {
-        this.dsg = BuilderGraph.buildDataset(maker.create(), SSE.parse(x1)) ;
-    }
-
-    @Test
-    public void union_dft_1t() {
-        union_dft_1(TRIPLES) ;
-    }
-    
-    @Test
-    public void union_dft_1q() {
-        union_dft_1(QUADS) ;
-    }
-    
-    private void union_dft_1(Mode mode) {
-        Op op = op("(bgp (?s ?p ?o))", mode) ;
-        List<Binding> results = exec(op) ;
-        assertEquals(5, results.size()) ;
-        Op op2 = Algebra.unionDefaultGraph(op) ;
-        List<Binding> results2 = exec(op2) ;
-        assertEquals(4, results2.size()) ;
-    }
-    
-    @Test
-    public void graph_union_1t() {
-        List<Binding> results = exec("(graph <" + Quad.unionGraph.getURI() + 
"> (bgp (<s2> ?p ?o)))", TRIPLES) ;
-        assertEquals(2, results.size()) ;
-    }
-
-    @Test
-    public void graph_union_1q() {
-        List<Binding> results = exec("(graph <" + Quad.unionGraph.getURI() + 
"> (bgp (<s2> ?p ?o)))", QUADS) ;
-        assertEquals(2, results.size()) ;
-    }
-
-    @Test
-    public void graph_union_2t() {
-        List<Binding> results = exec("(graph <" + Quad.unionGraph.getURI() + 
"> (bgp (<s1> ?p ?o) (?o ?q ?z)  ))", TRIPLES) ;
-        assertEquals(4, results.size()) ;
-    }
-
-    @Test
-    public void graph_union_2q() {
-        List<Binding> results = exec("(graph <" + Quad.unionGraph.getURI() + 
"> (bgp (<s1> ?p ?o) (?o ?q ?z)  ))", QUADS) ;
-        assertEquals(4, results.size()) ;
-    }
-
-    @Test
-    public void graph_dft_1t() {
-        List<Binding> results = exec("(graph <" + 
Quad.defaultGraphIRI.getURI() + "> (bgp (<s2> ?p ?o)))", TRIPLES) ;
-        assertEquals(0, results.size()) ;
-    }
-
-    @Test
-    public void graph_dft_1q() {
-        List<Binding> results = exec("(graph <" + 
Quad.defaultGraphIRI.getURI() + "> (bgp (<s2> ?p ?o)))", QUADS) ;
-        assertEquals(0, results.size()) ;
-    }
-
-    @Test
-    public void graph_dft_2t() {
-        List<Binding> results = exec("(graph <" + 
Quad.defaultGraphIRI.getURI() + "> (bgp (<s> ?p ?o)))", TRIPLES) ;
-        assertEquals(1, results.size()) ;
-    }
-
-    @Test
-    public void graph_dft_2q() {
-        List<Binding> results = exec("(graph <" + 
Quad.defaultGraphIRI.getURI() + "> (bgp (<s> ?p ?o)))", QUADS) ;
-        assertEquals(1, results.size()) ;
-    }
-
-    @Test
-    public void graph_dft_3t() {
-        List<Binding> results = exec("(graph <" + 
Quad.defaultGraphIRI.getURI() + "> (bgp (?x ?p ?z) (?z ?q ?y) ))", TRIPLES) ;
-        assertEquals(1, results.size()) ;
-    }
-
-    @Test
-    public void graph_dft_3q() {
-        List<Binding> results = exec("(graph <" + 
Quad.defaultGraphIRI.getURI() + "> (bgp (?x ?p ?z) (?z ?q ?y) ))", QUADS) ;
-        assertEquals(1, results.size()) ;
-    }
-
-    @Test
-    public void graph_dftg_1t() {
-        List<Binding> results = exec("(graph <" + 
Quad.defaultGraphNodeGenerated.getURI() + "> (bgp (<s2> ?p ?o)))", TRIPLES) ;
-        assertEquals(0, results.size()) ;
-    }
-    
-    @Test
-    public void graph_dftg_2t() {
-        List<Binding> results = exec("(graph <" + 
Quad.defaultGraphNodeGenerated.getURI() + "> (bgp (<x2> ?p ?o)))", TRIPLES) ;
-        assertEquals(3, results.size()) ;
-    }
-    
-    @Test
-    public void graph_dftg_1q() {
-        List<Binding> results = exec("(graph <" + 
Quad.defaultGraphNodeGenerated.getURI() + "> (bgp (<s2> ?p ?o)))", QUADS) ;
-        assertEquals(0, results.size()) ;
-    }
-
-    @Test
-    public void graph_dftg_2q() {
-        List<Binding> results = exec("(graph <" + 
Quad.defaultGraphNodeGenerated.getURI() + "> (bgp (<x2> ?p ?o)))", QUADS) ;
-        assertEquals(3, results.size()) ;
-    }
-
-    @Test
-    public void direct_3t() {
-        List<Binding> results = exec("(graph <g1> (bgp (<s1> ?p ?o)))", 
TRIPLES) ;
-        assertEquals(2, results.size()) ;
-    }
-
-    @Test
-    public void direct_3q() {
-        List<Binding> results = exec("(graph <g1> (bgp (<s1> ?p ?o)))", QUADS) 
;
-        assertEquals(2, results.size()) ;
-    }
-
-    @Test
-    public void direct_4() {
-        List<Binding> results = exec("(graph <g1> (bgp (<s2> ?p ?o)))", 
TRIPLES) ;
-        assertEquals(0, results.size()) ;
-    }
-
-    @Test
-    public void direct_5() {
-        List<Binding> results = exec("(graph <g2> (bgp (<s2> ?p ?o)))", 
TRIPLES) ;
-        assertEquals(2, results.size()) ;
-    }
-
-    private List<Binding> exec(String string, Mode mode) {
-        Op op = op(string, mode) ;
-        return exec(op) ;
-    }
-    
-    private List<Binding> exec(Op op) {
-        QueryIterator qIter = Algebra.exec(op, dsg) ;
-        return Iter.toList(qIter) ;
-    }
-
-    protected Op op(String pattern, Mode mode) {
-        Op op = SSE.parseOp(pattern) ;
-        if ( mode == Mode.QUADS )
-            op = Algebra.toQuadForm(op) ;
-        return op ;
-    }
-}

http://git-wip-us.apache.org/repos/asf/jena/blob/3046d091/jena-arq/src/test/java/org/apache/jena/sparql/core/TestSpecials.java
----------------------------------------------------------------------
diff --git 
a/jena-arq/src/test/java/org/apache/jena/sparql/core/TestSpecials.java 
b/jena-arq/src/test/java/org/apache/jena/sparql/core/TestSpecials.java
new file mode 100644
index 0000000..b2ac2ad
--- /dev/null
+++ b/jena-arq/src/test/java/org/apache/jena/sparql/core/TestSpecials.java
@@ -0,0 +1,288 @@
+/*
+ * 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.core;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import org.apache.jena.graph.Graph;
+import org.apache.jena.graph.Node;
+import org.apache.jena.graph.TransactionHandler;
+import org.apache.jena.graph.Triple;
+import org.apache.jena.query.ReadWrite;
+import org.apache.jena.shared.JenaException;
+import org.apache.jena.sparql.JenaTransactionException;
+import org.apache.jena.sparql.graph.GraphFactory;
+import org.apache.jena.sparql.graph.GraphSink;
+import org.apache.jena.sparql.graph.GraphZero;
+import org.apache.jena.sparql.sse.SSE;
+import org.apache.jena.system.Txn;
+import org.junit.Test;
+
+/** Tests for
+ * {@link DatasetGraphZero},
+ * {@link DatasetGraphSink} and
+ * {@link DatasetGraphOne}
+ * and (via their use in datasets):
+ * {@link GraphZero} and
+ * {@link GraphSink}
+*/
+public class TestSpecials {
+    
+    private static Quad quad = SSE.parseQuad("(:g :s :p :o)");
+    private static Triple triple = SSE.parseTriple("(:s :p :o)");
+    private static Node gn = SSE.parseNode(":gn");
+    
+    // -- zero
+    
+    @Test public void zero_basic_1() {
+        DatasetGraph dsg = DatasetGraphZero.create();
+        assertFalse(dsg.find().hasNext());
+        assertTrue(dsg.supportsTransactionAbort());
+        assertEquals(0, dsg.getDefaultGraph().size());
+        assertFalse(dsg.getDefaultGraph().getCapabilities().addAllowed());
+    }
+    
+    @Test public void zero_basic_2() {
+        DatasetGraph dsg = DatasetGraphZero.create();
+        assertNull(dsg.getGraph(gn));
+    }
+    
+    @Test(expected=UnsupportedOperationException.class)
+    public void zero_add_1() {
+        DatasetGraph dsg = DatasetGraphZero.create();
+        dsg.add(quad);
+    }
+
+    @Test(expected=UnsupportedOperationException.class)
+    public void zero_add_2() {
+        DatasetGraph dsg = DatasetGraphZero.create();
+        dsg.getDefaultGraph().add(triple);
+    }
+
+    @Test(expected=UnsupportedOperationException.class)
+    public void zero_add_3() {
+        DatasetGraph dsg = DatasetGraphZero.create();
+        dsg.addGraph(gn, GraphFactory.createGraphMem());
+    }
+
+    @Test(expected=UnsupportedOperationException.class)
+    public void zero_delete_1() {
+        DatasetGraph dsg = DatasetGraphZero.create();
+        dsg.delete(quad);
+    }
+
+    @Test(expected=UnsupportedOperationException.class)
+    public void zero_delete_2() {
+        DatasetGraph dsg = DatasetGraphZero.create();
+        dsg.getDefaultGraph().delete(triple);
+    }
+
+    @Test(expected=UnsupportedOperationException.class)
+    public void zero_delete_3() {
+        DatasetGraph dsg = DatasetGraphZero.create();
+        dsg.deleteAny(Node.ANY, Node.ANY, Node.ANY, Node.ANY);
+    }
+
+    @Test public void zero_txn_1() {
+        DatasetGraph dsg = DatasetGraphZero.create();
+        Txn.executeRead(dsg, ()->{});
+        Txn.executeWrite(dsg, ()->{});
+    }
+
+    @Test(expected=JenaTransactionException.class)
+    public void zero_txn_2() {
+        DatasetGraph dsg = DatasetGraphZero.create();
+        dsg.begin(ReadWrite.READ);
+        dsg.begin(ReadWrite.READ);
+    }
+
+    @Test(expected=JenaTransactionException.class)
+    public void zero_txn_3() {
+        DatasetGraph dsg = DatasetGraphZero.create();
+        dsg.commit();
+    }
+    
+    @Test(expected=JenaTransactionException.class)
+    public void zero_txn_4() {
+        DatasetGraph dsg = DatasetGraphZero.create();
+        dsg.begin(ReadWrite.WRITE);
+        dsg.commit();
+        dsg.commit();
+    }
+    
+    @Test public void zero_graph_txn_1() {
+        DatasetGraph dsg = DatasetGraphZero.create();
+        Graph g = dsg.getDefaultGraph();
+        g.getTransactionHandler().execute(()->{});
+    }
+
+    @Test public void zero_graph_txn_2() {
+        DatasetGraph dsg = DatasetGraphZero.create();
+        Graph g = dsg.getDefaultGraph();
+        TransactionHandler h = g.getTransactionHandler();
+        h.begin();
+        h.abort();
+    }
+
+    @Test(expected=JenaException.class)
+    public void zero_graph_txn_3() {
+        DatasetGraph dsg = DatasetGraphZero.create();
+        Graph g = dsg.getDefaultGraph();
+        TransactionHandler h = g.getTransactionHandler();
+        h.begin();
+        h.begin();
+    }
+
+    @Test(expected=JenaException.class)
+    public void zero_graph_txn_4() {
+        DatasetGraph dsg = DatasetGraphZero.create();
+        Graph g = dsg.getDefaultGraph();
+        TransactionHandler h = g.getTransactionHandler();
+        h.begin();
+        h.commit();
+        h.abort();
+    }
+
+    @Test(expected=JenaException.class)
+    public void zero_graph_txn_5() {
+        DatasetGraph dsg = DatasetGraphZero.create();
+        Graph g = dsg.getDefaultGraph();
+        TransactionHandler h = g.getTransactionHandler();
+        h.commit();
+    }
+    
+    // -- sink
+    
+    @Test public void sink_basic_1() {
+        DatasetGraph dsg = DatasetGraphSink.create();
+        assertFalse(dsg.find().hasNext());
+        assertTrue(dsg.supportsTransactionAbort());
+        assertEquals(0, dsg.getDefaultGraph().size());
+        assertTrue(dsg.getDefaultGraph().getCapabilities().addAllowed());
+    }
+    
+    @Test public void sink_basic_2() {
+        DatasetGraph dsg = DatasetGraphSink.create();
+        assertNull(dsg.getGraph(gn));
+    }
+    
+    @Test public void sink_add_1() {
+        DatasetGraph dsg = DatasetGraphSink.create();
+        dsg.add(quad);
+    }
+
+    @Test public void sink_add_2() {
+        DatasetGraph dsg = DatasetGraphSink.create();
+        dsg.getDefaultGraph().add(triple);
+    }
+
+    @Test
+    public void sink_add_3() {
+        DatasetGraph dsg = DatasetGraphSink.create();
+        dsg.addGraph(gn, GraphFactory.createGraphMem());
+    }
+
+    @Test public void sink_delete_1() {
+        DatasetGraph dsg = DatasetGraphSink.create();
+        dsg.add(quad);
+    }
+
+    @Test public void sink_delete_2() {
+        DatasetGraph dsg = DatasetGraphSink.create();
+        dsg.getDefaultGraph().add(triple);
+    }
+    
+    @Test
+    public void sink_delete_3() {
+        DatasetGraph dsg = DatasetGraphSink.create();
+        dsg.deleteAny(Node.ANY, Node.ANY, Node.ANY, Node.ANY);
+    }
+
+    @Test public void sink_txn_1() {
+        DatasetGraph dsg = DatasetGraphSink.create();
+        Txn.executeRead(dsg, ()->{});
+        Txn.executeWrite(dsg, ()->{});
+    }
+    
+    @Test(expected=JenaTransactionException.class)
+    public void sink_txn_2() {
+        DatasetGraph dsg = DatasetGraphSink.create();
+        dsg.begin(ReadWrite.READ);
+        dsg.begin(ReadWrite.READ);
+    }
+
+    @Test(expected=JenaTransactionException.class)
+    public void sink_txn_3() {
+        DatasetGraph dsg = DatasetGraphSink.create();
+        dsg.commit();
+    }
+    
+    @Test(expected=JenaTransactionException.class)
+    public void sink_txn_4() {
+        DatasetGraph dsg = DatasetGraphSink.create();
+        dsg.begin(ReadWrite.WRITE);
+        dsg.commit();
+        dsg.commit();
+    }
+    
+    @Test public void sink_graph_txn_1() {
+        DatasetGraph dsg = DatasetGraphSink.create();
+        Graph g = dsg.getDefaultGraph();
+        g.getTransactionHandler().execute(()->{});
+    }
+
+
+    @Test public void sink_graph_txn_2() {
+        DatasetGraph dsg = DatasetGraphSink.create();
+        Graph g = dsg.getDefaultGraph();
+        TransactionHandler h = g.getTransactionHandler();
+        h.begin();
+        h.abort();
+    }
+
+    @Test(expected=JenaException.class)
+    public void sink_graph_txn_3() {
+        DatasetGraph dsg = DatasetGraphSink.create();
+        Graph g = dsg.getDefaultGraph();
+        TransactionHandler h = g.getTransactionHandler();
+        h.begin();
+        h.begin();
+    }
+
+    @Test(expected=JenaException.class)
+    public void sink_graph_txn_4() {
+        DatasetGraph dsg = DatasetGraphSink.create();
+        Graph g = dsg.getDefaultGraph();
+        TransactionHandler h = g.getTransactionHandler();
+        h.begin();
+        h.commit();
+        h.abort();
+    }
+
+    @Test(expected=JenaException.class)
+    public void sink_graph_txn_5() {
+        DatasetGraph dsg = DatasetGraphSink.create();
+        Graph g = dsg.getDefaultGraph();
+        TransactionHandler h = g.getTransactionHandler();
+        h.commit();
+    }
+}

Reply via email to