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

commit c83e440e2277d674319a2be4d9dcb559f4b4a0a2
Author: Andy Seaborne <[email protected]>
AuthorDate: Sun Feb 15 16:04:09 2026 +0000

    GH-3751: OpExecutorTDB: Test input on entry. Wrap in QueryIterFailed 
handling
---
 .../sparql/engine/main/StageGeneratorGeneric.java  |  48 ++--
 .../apache/jena/tdb1/solver/OpExecutorTDB1.java    | 163 ++++++--------
 .../jena/tdb1/solver/StageGeneratorDirectTDB.java  |  39 ++--
 .../apache/jena/tdb1/store/Test_SPARQL_TDB1.java   |  21 +-
 .../apache/jena/tdb2/solver/OpExecutorTDB2.java    | 243 +++++++++------------
 .../jena/tdb2/solver/StageGeneratorDirectTDB.java  |   2 +-
 .../apache/jena/tdb2/store/Test_SPARQL_TDB.java    | 117 +++++-----
 7 files changed, 292 insertions(+), 341 deletions(-)

diff --git 
a/jena-arq/src/main/java/org/apache/jena/sparql/engine/main/StageGeneratorGeneric.java
 
b/jena-arq/src/main/java/org/apache/jena/sparql/engine/main/StageGeneratorGeneric.java
index 2ddb212fb4..14092374c6 100644
--- 
a/jena-arq/src/main/java/org/apache/jena/sparql/engine/main/StageGeneratorGeneric.java
+++ 
b/jena-arq/src/main/java/org/apache/jena/sparql/engine/main/StageGeneratorGeneric.java
@@ -63,38 +63,30 @@ public class StageGeneratorGeneric implements 
StageGenerator {
     protected QueryIterator execute(BasicPattern pattern, 
ReorderTransformation reorder,
                                     QueryIterator input, ExecutionContext 
execCxt) {
         Explain.explain(pattern, execCxt.getContext()) ;
+        try {
+            if ( ! input.hasNext() )
+                return input ;
 
-         if ( reorder != null && pattern.size() >= 2 ) {
-            // If pattern size is 0 or 1, nothing to do.
-            BasicPattern bgp2 = pattern ;
+            if ( reorder != null && pattern.size() >= 2 ) {
+                // If pattern size is 0 or 1, nothing to do.
+                BasicPattern bgp2 = pattern ;
 
-            // Try to ground the pattern
-            if ( ! input.isJoinIdentity() ) {
-                QueryIterPeek peek = QueryIterPeek.create(input, execCxt) ;
-                // And now use this one
-                input = peek ;
-                Binding b ;
-                // Eager access may fail e.g. due to timeout.
-                try {
-                    b = peek.peek() ;
-                } catch (Exception e) {
-                    return new QueryIterFailed(input, execCxt, e);
+                // Try to ground the pattern
+                if ( ! input.isJoinIdentity() ) {
+                    QueryIterPeek peek = QueryIterPeek.create(input, execCxt) ;
+                    // And now use this one
+                    input = peek ;
+                    Binding b = peek.peek() ;
+                    bgp2 = Substitute.substitute(pattern, b) ;
                 }
-                bgp2 = Substitute.substitute(pattern, b) ;
+                ReorderProc reorderProc = reorder.reorderIndexes(bgp2) ;
+                pattern = reorderProc.reorder(pattern) ;
             }
-            ReorderProc reorderProc = reorder.reorderIndexes(bgp2) ;
-            pattern = reorderProc.reorder(pattern) ;
-        } else {
-            // Eager access may fail e.g. due to timeout.
-            try {
-                if ( ! input.hasNext() )
-                    return input ;
-            } catch (Exception e) {
-                return new QueryIterFailed(input, execCxt, e);
-            }
-        }
 
-        Explain.explain("Reorder/generic", pattern, execCxt.getContext()) ;
-        return PatternMatchData.execute(execCxt.getActiveGraph(), pattern, 
input, null, execCxt) ;
+            Explain.explain("Reorder/generic", pattern, execCxt.getContext()) ;
+            return PatternMatchData.execute(execCxt.getActiveGraph(), pattern, 
input, null, execCxt) ;
+        } catch (Exception e) {
+            return new QueryIterFailed(input, execCxt, e);
+        }
     }
 }
diff --git 
a/jena-tdb1/src/main/java/org/apache/jena/tdb1/solver/OpExecutorTDB1.java 
b/jena-tdb1/src/main/java/org/apache/jena/tdb1/solver/OpExecutorTDB1.java
index 9b41596b53..a7eff6f9fc 100644
--- a/jena-tdb1/src/main/java/org/apache/jena/tdb1/solver/OpExecutorTDB1.java
+++ b/jena-tdb1/src/main/java/org/apache/jena/tdb1/solver/OpExecutorTDB1.java
@@ -27,7 +27,6 @@ import org.apache.jena.atlas.lib.tuple.Tuple;
 import org.apache.jena.atlas.logging.Log;
 import org.apache.jena.graph.Graph;
 import org.apache.jena.graph.Node;
-import org.apache.jena.sparql.ARQInternalErrorException;
 import org.apache.jena.sparql.algebra.Op;
 import org.apache.jena.sparql.algebra.op.*;
 import org.apache.jena.sparql.algebra.optimize.TransformFilterPlacement;
@@ -42,6 +41,7 @@ import org.apache.jena.sparql.engine.iterator.QueryIterPeek;
 import org.apache.jena.sparql.engine.main.OpExecutor;
 import org.apache.jena.sparql.engine.main.OpExecutorFactory;
 import org.apache.jena.sparql.engine.main.QC;
+import org.apache.jena.sparql.engine.main.StageGenerator;
 import org.apache.jena.sparql.engine.main.iterator.QueryIterGraph;
 import org.apache.jena.sparql.engine.optimizer.reorder.ReorderProc;
 import org.apache.jena.sparql.engine.optimizer.reorder.ReorderTransformation;
@@ -53,28 +53,28 @@ import org.apache.jena.tdb1.store.NodeId;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-/** TDB executor for algebra expressions.  It is the standard ARQ executor
- *  except for basic graph patterns and filtered basic graph patterns 
(currently).
+/**
+ * TDB1 executor for algebra expressions.  It is the standard ARQ executor
+ * except for basic graph patterns and filtered basic graph patterns 
(currently).
  *
- * See also: StageGeneratorDirectTDB, a non-reordering
+ * See also: {@link StageGeneratorDirectTDB}, a non-reordering {@link 
StageGenerator}
  */
 public class OpExecutorTDB1 extends OpExecutor
 {
     private static final Logger log = 
LoggerFactory.getLogger(OpExecutorTDB1.class);
 
-    public final static OpExecutorFactory OpExecFactoryTDB = new 
OpExecutorFactory()
-    {
+    public final static OpExecutorFactory OpExecFactoryTDB = new 
OpExecutorFactory() {
         @Override
-        public OpExecutor create(ExecutionContext execCxt)
-        { return new OpExecutorTDB1(execCxt); }
+        public OpExecutor create(ExecutionContext execCxt) {
+            return new OpExecutorTDB1(execCxt);
+        }
     };
 
     private final boolean isForTDB;
 
     // A new compile object is created for each op compilation.
     // So the execCxt is changing as we go through the query-compile-execute 
process
-    public OpExecutorTDB1(ExecutionContext execCxt)
-    {
+    public OpExecutorTDB1(ExecutionContext execCxt) {
         super(execCxt);
         // NB. The dataset may be a TDB one, or a general one.
         // Any merged union graph magic (for a TDB dataset was handled
@@ -92,8 +92,7 @@ public class OpExecutorTDB1 extends OpExecutor
     }
 
     @Override
-    protected QueryIterator execute(OpFilter opFilter, QueryIterator input)
-    {
+    protected QueryIterator execute(OpFilter opFilter, QueryIterator input) {
         if ( ! isForTDB )
             return super.execute(opFilter, input);
 
@@ -101,8 +100,7 @@ public class OpExecutorTDB1 extends OpExecutor
         // Where does ARQ catch this?
 
         // (filter (bgp ...))
-        if ( OpBGP.isBGP(opFilter.getSubOp()) )
-        {
+        if ( OpBGP.isBGP(opFilter.getSubOp()) ) {
             // Still may be a TDB graph in a non-TDB dataset (e.g. a named 
model)
             GraphTDB graph = (GraphTDB)execCxt.getActiveGraph();
             OpBGP opBGP = (OpBGP)opFilter.getSubOp();
@@ -110,24 +108,20 @@ public class OpExecutorTDB1 extends OpExecutor
         }
 
         // (filter (quadpattern ...))
-        if ( opFilter.getSubOp() instanceof OpQuadPattern quadPattern )
-        {
+        if ( opFilter.getSubOp() instanceof OpQuadPattern quadPattern ) {
             DatasetGraphTDB ds = (DatasetGraphTDB)execCxt.getDataset();
-            return optimizeExecuteQuads(ds, input,
-                                        quadPattern.getGraphNode(), 
quadPattern.getBasicPattern(),
-                                        opFilter.getExprs(), execCxt);
+            return optimizeExecuteQuads(ds, input, quadPattern.getGraphNode(), 
quadPattern.getBasicPattern(), opFilter.getExprs(), execCxt);
         }
 
         // (filter (anything else))
         return super.execute(opFilter, input);
-        }
+    }
 
     // ---- Triple patterns
 
     @Override
-    protected QueryIterator execute(OpBGP opBGP, QueryIterator input)
-    {
-        if ( ! isForTDB )
+    protected QueryIterator execute(OpBGP opBGP, QueryIterator input) {
+        if ( !isForTDB )
             return super.execute(opBGP, input);
 
         GraphTDB graph = (GraphTDB)execCxt.getActiveGraph();
@@ -136,15 +130,9 @@ public class OpExecutorTDB1 extends OpExecutor
     }
 
     @Override
-    protected QueryIterator execute(OpQuadPattern quadPattern, QueryIterator 
input)
-    {
-        if ( ! isForTDB )
+    protected QueryIterator execute(OpQuadPattern quadPattern, QueryIterator 
input) {
+        if ( !isForTDB )
             return super.execute(quadPattern, input);
-
-    //        DatasetGraph dg = execCxt.getDataset();
-    //        if ( ! ( dg instanceof DatasetGraphTDB ) )
-    //            throw new InternalErrorException("Not a TDB backed dataset 
in quad pattern execution");
-
         DatasetGraphTDB ds = (DatasetGraphTDB)execCxt.getDataset();
         BasicPattern bgp = quadPattern.getBasicPattern();
         Node gn = quadPattern.getGraphNode();
@@ -152,16 +140,15 @@ public class OpExecutorTDB1 extends OpExecutor
     }
 
     @Override
-    protected QueryIterator execute(OpGraph opGraph, QueryIterator input)
-    {
-        // Path evaluation or dataset sets which do not go straight to the 
DatasetGraphTDB
+    protected QueryIterator execute(OpGraph opGraph, QueryIterator input) {
+        // Path evaluation or dataset sets which do not go straight to the
+        // DatasetGraphTDB
         return new QueryIterGraph(input, opGraph, execCxt);
     }
 
     /** Execute a BGP (and filters) on a TDB graph, which may be in default 
storage or it may be a named graph */
     private static QueryIterator executeBGP(GraphTDB graph, OpBGP opBGP, 
QueryIterator input, ExprList exprs,
-                                            ExecutionContext execCxt)
-    {
+                                            ExecutionContext execCxt) {
         DatasetGraphTDB dsgtdb = graph.getDatasetGraphTDB();
         // Is it the real default graph (normal route or explicitly named)?
         if ( ! isDefaultGraphStorage(graph.getGraphName()))
@@ -177,10 +164,11 @@ public class OpExecutorTDB1 extends OpExecutor
     /** Execute, with optimization, a basic graph pattern on the default graph 
storage */
     private static QueryIterator optimizeExecuteTriples(DatasetGraphTDB 
dsgtdb, QueryIterator input,
                                                         BasicPattern pattern, 
ExprList exprs,
-                                                        ExecutionContext 
execCxt)
-    {
-        if ( ! input.hasNext() )
-            return input;
+                                                        ExecutionContext 
execCxt) {
+        try {
+            if ( ! input.hasNext() )
+                return input;
+        } catch (Exception ex) { return new QueryIterFailed(input, execCxt, 
ex); }
 
         // -- Input
         // Must pass this iterator into the next stage.
@@ -188,8 +176,7 @@ public class OpExecutorTDB1 extends OpExecutor
         {
             // Must be 2 or triples to reorder.
             ReorderTransformation transform = dsgtdb.getReorderTransform();
-            if ( transform != null )
-            {
+            if ( transform != null ) {
                 QueryIterPeek peek = QueryIterPeek.create(input, execCxt);
                 input = peek; // Must pass on
                 try {
@@ -211,24 +198,23 @@ public class OpExecutorTDB1 extends OpExecutor
     }
 
     /** Execute, with optimization, a quad pattern */
-    private static QueryIterator optimizeExecuteQuads(DatasetGraphTDB dsgtdb,
-                                                      QueryIterator input,
-                                                      Node gn, BasicPattern 
bgp,
-                                                      ExprList exprs, 
ExecutionContext execCxt)
-    {
-        // ---- Graph names with special meaning.
+    private static QueryIterator optimizeExecuteQuads(DatasetGraphTDB dsgtdb, 
QueryIterator input,
+                                                      Node gn, BasicPattern 
bgp, ExprList exprs, ExecutionContext execCxt) {
+        try {
+            if ( ! input.hasNext() )
+                return input;
+        } catch (Exception ex) { return new QueryIterFailed(input, execCxt, 
ex); }
 
+        // ---- Graph names with special meaning.
         gn = decideGraphNode(gn, execCxt);
         if ( gn == null )
             return optimizeExecuteTriples(dsgtdb, input, bgp, exprs, execCxt);
 
         // ---- Execute quads+filters
-        if ( bgp.size() >= 2 )
-        {
+        if ( bgp.size() >= 2 ) {
             ReorderTransformation transform = dsgtdb.getReorderTransform();
 
-            if ( transform != null )
-            {
+            if ( transform != null ) {
                 QueryIterPeek peek = QueryIterPeek.create(input, execCxt);
                 input = peek; // Original input now invalid.
                 try {
@@ -237,13 +223,6 @@ public class OpExecutorTDB1 extends OpExecutor
                     return new QueryIterFailed(input, execCxt, e);
                 }
             }
-        } else {
-            try {
-                if ( ! input.hasNext() )
-                    return input;
-            } catch (Exception e) {
-                return new QueryIterFailed(input, execCxt, e);
-            }
         }
 
         if ( exprs == null ) {
@@ -257,9 +236,12 @@ public class OpExecutorTDB1 extends OpExecutor
         Op op = TransformFilterPlacement.transform(exprs, gn, bgp);
         return plainExecute(op, input, execCxt);
     }
-    /** Execute without modification of the op - does <b>not</b> apply special 
graph name translations */
-    private static QueryIterator plainExecute(Op op, QueryIterator input, 
ExecutionContext execCxt)
-    {
+
+    /**
+     * Execute without modification of the op - does <b>not</b> apply special 
graph
+     * name translations
+     */
+    private static QueryIterator plainExecute(Op op, QueryIterator input, 
ExecutionContext execCxt) {
         // -- Execute
         // Switch to a non-reordering executor
         // The Op may be a sequence due to TransformFilterPlacement
@@ -275,23 +257,19 @@ public class OpExecutorTDB1 extends OpExecutor
         return QC.execute(op, input, ec2);
     }
 
-    private static BasicPattern reorder(BasicPattern pattern, QueryIterPeek 
peek, ReorderTransformation transform)
-    {
-        if ( transform != null )
-        {
+    private static BasicPattern reorder(BasicPattern pattern, QueryIterPeek 
peek, ReorderTransformation transform) {
+        // Caller tested that peek.hasNext is true.
+        if ( transform != null ) {
             // This works by getting one result from the peek iterator,
             // and creating the more gounded BGP. The tranform is used to
             // determine the best order and the transformation is returned. 
This
             // transform is applied to the unsubstituted pattern (which will be
             // substituted as part of evaluation.
 
-            if ( ! peek.hasNext() )
-                throw new ARQInternalErrorException("Peek iterator is already 
empty");
-
             BasicPattern pattern2 = Substitute.substitute(pattern, peek.peek() 
);
             // Calculate the reordering based on the substituted pattern.
             ReorderProc proc = transform.reorderIndexes(pattern2);
-            // Then reorder original patten
+            // Then reorder original pattern
             pattern = proc.reorder(pattern);
         }
         return pattern;
@@ -301,17 +279,15 @@ public class OpExecutorTDB1 extends OpExecutor
      * Returns null for default graph in storage (use the triple table).
      * Returns Node.ANY for the union graph
      */
-    public static Node decideGraphNode(Node gn, ExecutionContext execCxt)
-    {
-     // ---- Graph names with special meaning.
+    public static Node decideGraphNode(Node gn, ExecutionContext execCxt) {
+        // ---- Graph names with special meaning.
 
         // Graph names with special meaning:
         //   Quad.defaultGraphIRI -- the IRI used in GRAPH <> to mean the 
default graph.
         //   Quad.defaultGraphNodeGenerated -- the internal marker node used 
for the quad form of queries.
         //   Quad.unionGraph -- the IRI used in GRAPH <> to mean the union of 
named graphs
 
-        if ( isDefaultGraphStorage(gn) )
-        {
+        if ( isDefaultGraphStorage(gn) ) {
             // Storage concrete, default graph.
             // Either outside GRAPH (no implicit union)
             // or using the "name" of the default graph
@@ -327,8 +303,7 @@ public class OpExecutorTDB1 extends OpExecutor
     }
 
     // Is this a query against the real default graph in the storage (in a 
3-tuple table).
-    private static boolean isDefaultGraphStorage(Node gn)
-    {
+    private static boolean isDefaultGraphStorage(Node gn) {
         if ( gn == null )
             return true;
 
@@ -342,8 +317,7 @@ public class OpExecutorTDB1 extends OpExecutor
     }
 
     @Override
-    protected QueryIterator execute(OpDatasetNames dsNames, QueryIterator 
input)
-    {
+    protected QueryIterator execute(OpDatasetNames dsNames, QueryIterator 
input) {
         DatasetGraphTDB ds = (DatasetGraphTDB)execCxt.getDataset();
         Predicate<Tuple<NodeId>> filter = QC2.getFilter(execCxt.getContext());
         Node gn = dsNames.getGraphNode();
@@ -356,8 +330,7 @@ public class OpExecutorTDB1 extends OpExecutor
     // ---- OpExecute factories and plain executor.
 
     private static OpExecutorFactory plainFactory = new 
OpExecutorPlainFactoryTDB();
-    private static class OpExecutorPlainFactoryTDB implements OpExecutorFactory
-    {
+    private static class OpExecutorPlainFactoryTDB implements 
OpExecutorFactory {
         @Override
         public OpExecutor create(ExecutionContext execCxt)
         {
@@ -366,27 +339,24 @@ public class OpExecutorTDB1 extends OpExecutor
     }
 
     /** An op executor that simply executes a BGP or QuadPattern without any 
reordering */
-    private static class OpExecutorPlainTDB extends OpExecutor
-    {
+    private static class OpExecutorPlainTDB extends OpExecutor {
         Predicate<Tuple<NodeId>> filter = null;
 
-        public OpExecutorPlainTDB(ExecutionContext execCxt)
-        {
+        public OpExecutorPlainTDB(ExecutionContext execCxt) {
             super(execCxt);
             filter = QC2.getFilter(execCxt.getContext());
         }
 
         @Override
-        public QueryIterator execute(OpBGP opBGP, QueryIterator input)
-        {
+        public QueryIterator execute(OpBGP opBGP, QueryIterator input) {
             Graph g = execCxt.getActiveGraph();
 
-            if ( g instanceof GraphTDB gtdb )
-            {
+            if ( g instanceof GraphTDB gtdb ) {
                 BasicPattern bgp = opBGP.getPattern();
                 Explain.explain("Execute", bgp, execCxt.getContext());
                 // Triple-backed (but may be named as explicit default graph).
-                //return SolverLib.execute((GraphTDB)g, bgp, input, filter, 
execCxt);
+                // return SolverLib.execute((GraphTDB)g, bgp, input, filter,
+                // execCxt);
                 Node gn = decideGraphNode(gtdb.getGraphName(), execCxt);
                 return PatternMatchTDB1.execute(gtdb.getDatasetGraphTDB(), gn, 
bgp, input, filter, execCxt);
             }
@@ -395,26 +365,23 @@ public class OpExecutorTDB1 extends OpExecutor
         }
 
         @Override
-        public QueryIterator execute(OpQuadPattern opQuadPattern, 
QueryIterator input)
-        {
+        public QueryIterator execute(OpQuadPattern opQuadPattern, 
QueryIterator input) {
             Node gn = opQuadPattern.getGraphNode();
             gn = decideGraphNode(gn, execCxt);
 
-            if ( execCxt.getDataset() instanceof DatasetGraphTDB dsgtdb )
-            {
+            if ( execCxt.getDataset() instanceof DatasetGraphTDB dsgtdb ) {
                 Explain.explain("Execute", opQuadPattern.getPattern(), 
execCxt.getContext());
                 BasicPattern bgp = opQuadPattern.getBasicPattern();
                 return PatternMatchTDB1.execute(dsgtdb, gn, bgp, input, 
filter, execCxt);
             }
             // Maybe a TDB named graph inside a non-TDB dataset.
             Graph g = execCxt.getActiveGraph();
-            if ( g instanceof GraphTDB gtdb )
-            {
-                // Triples graph from TDB (which is the default graph of the 
dataset),
+            if ( g instanceof GraphTDB gtdb ) {
+                // Triples graph from TDB, which is the default graph of the 
dataset,
                 // used a named graph in a composite dataset.
                 BasicPattern bgp = opQuadPattern.getBasicPattern();
                 Explain.explain("Execute", bgp, execCxt.getContext());
-                // Don't pass in G -- gn may be different.
+                // Don't pass in g -- gn may be different.
                 return PatternMatchTDB1.execute(gtdb.getDatasetGraphTDB(), gn, 
bgp, input, filter, execCxt);
             }
             Log.warn(this, "Non-DatasetGraphTDB passed to OpExecutorPlainTDB");
diff --git 
a/jena-tdb1/src/main/java/org/apache/jena/tdb1/solver/StageGeneratorDirectTDB.java
 
b/jena-tdb1/src/main/java/org/apache/jena/tdb1/solver/StageGeneratorDirectTDB.java
index 10f9cc13f2..96b45966ea 100644
--- 
a/jena-tdb1/src/main/java/org/apache/jena/tdb1/solver/StageGeneratorDirectTDB.java
+++ 
b/jena-tdb1/src/main/java/org/apache/jena/tdb1/solver/StageGeneratorDirectTDB.java
@@ -23,38 +23,35 @@ package org.apache.jena.tdb1.solver;
 
 import java.util.function.Predicate;
 
-import org.apache.jena.atlas.lib.tuple.Tuple ;
-import org.apache.jena.graph.Graph ;
-import org.apache.jena.sparql.core.BasicPattern ;
-import org.apache.jena.sparql.engine.ExecutionContext ;
-import org.apache.jena.sparql.engine.QueryIterator ;
-import org.apache.jena.sparql.engine.main.StageGenerator ;
+import org.apache.jena.atlas.lib.tuple.Tuple;
+import org.apache.jena.graph.Graph;
+import org.apache.jena.sparql.core.BasicPattern;
+import org.apache.jena.sparql.engine.ExecutionContext;
+import org.apache.jena.sparql.engine.QueryIterator;
+import org.apache.jena.sparql.engine.main.StageGenerator;
 import org.apache.jena.tdb1.store.GraphTDB;
 import org.apache.jena.tdb1.store.NodeId;
 
-/** Execute TDB requests directly -- no reordering
- *  Using OpExecutor is preferred.
+/**
+ * Execute TDB requests directly -- no reordering. Using OpExecutor is 
preferred.
  */
-public class StageGeneratorDirectTDB implements StageGenerator
-{
+public class StageGeneratorDirectTDB implements StageGenerator {
     // Using OpExecutor is preferred.
-    StageGenerator above = null ;
+    StageGenerator above = null;
 
-    public StageGeneratorDirectTDB(StageGenerator original)
-    {
-        above = original ;
+    public StageGeneratorDirectTDB(StageGenerator original) {
+        above = original;
     }
 
     @Override
-    public QueryIterator execute(BasicPattern pattern, QueryIterator input, 
ExecutionContext execCxt)
-    {
+    public QueryIterator execute(BasicPattern pattern, QueryIterator input, 
ExecutionContext execCxt) {
         // --- In case this isn't for TDB
-        Graph g = execCxt.getActiveGraph() ;
+        Graph g = execCxt.getActiveGraph();
 
-        if ( ! ( g instanceof GraphTDB graph) )
+        if ( !(g instanceof GraphTDB graph) )
             // Not us - bounce up the StageGenerator chain
-            return above.execute(pattern, input, execCxt) ;
-        Predicate<Tuple<NodeId>> filter = QC2.getFilter(execCxt.getContext()) ;
-        return PatternMatchTDB1.execute(graph, pattern, input, filter, 
execCxt) ;
+            return above.execute(pattern, input, execCxt);
+        Predicate<Tuple<NodeId>> filter = QC2.getFilter(execCxt.getContext());
+        return PatternMatchTDB1.execute(graph, pattern, input, filter, 
execCxt);
     }
 }
diff --git 
a/jena-tdb1/src/test/java/org/apache/jena/tdb1/store/Test_SPARQL_TDB1.java 
b/jena-tdb1/src/test/java/org/apache/jena/tdb1/store/Test_SPARQL_TDB1.java
index 2a5fffcc38..4539b39c6f 100644
--- a/jena-tdb1/src/test/java/org/apache/jena/tdb1/store/Test_SPARQL_TDB1.java
+++ b/jena-tdb1/src/test/java/org/apache/jena/tdb1/store/Test_SPARQL_TDB1.java
@@ -23,6 +23,8 @@ package org.apache.jena.tdb1.store;
 
 import static org.junit.Assert.assertEquals;
 
+import org.junit.Test ;
+
 import org.apache.jena.atlas.lib.StrUtils ;
 import org.apache.jena.graph.Graph ;
 import org.apache.jena.graph.NodeFactory ;
@@ -30,6 +32,10 @@ import org.apache.jena.graph.Triple ;
 import org.apache.jena.query.* ;
 import org.apache.jena.rdf.model.Model ;
 import org.apache.jena.rdf.model.ModelFactory ;
+import org.apache.jena.sparql.core.DatasetGraph;
+import org.apache.jena.sparql.exec.QueryExec;
+import org.apache.jena.sparql.exec.RowSet;
+import org.apache.jena.sparql.exec.RowSetOps;
 import org.apache.jena.sparql.exec.UpdateExec;
 import org.apache.jena.sparql.sse.SSE ;
 import org.apache.jena.system.Txn;
@@ -39,7 +45,6 @@ import org.apache.jena.tdb1.base.file.Location;
 import org.apache.jena.update.UpdateAction;
 import org.apache.jena.update.UpdateFactory;
 import org.apache.jena.update.UpdateRequest;
-import org.junit.Test ;
 
 /**
  * Test SPARQL
@@ -152,6 +157,20 @@ public class Test_SPARQL_TDB1
         assertEquals(false, b);
     }
 
+    @Test
+    public void sparql7() {
+        // https://github.com/apache/jena/issues/3751
+        String qs = """
+                PREFIX : <http://example/>
+                SELECT * { ?x :property+ ?y . ?z :q1 123 . ?z :q2 456 . }
+                """;
+        DatasetGraph dsg = TDB1Factory.createDatasetGraph();
+        dsg.executeRead(()->{
+            RowSet rs = QueryExec.dataset(dsg).query(qs).select();
+            RowSetOps.consume(rs);
+        });
+    }
+
     // Test transactions effective.
 
     @Test
diff --git 
a/jena-tdb2/src/main/java/org/apache/jena/tdb2/solver/OpExecutorTDB2.java 
b/jena-tdb2/src/main/java/org/apache/jena/tdb2/solver/OpExecutorTDB2.java
index 2273e07bae..23c649d348 100644
--- a/jena-tdb2/src/main/java/org/apache/jena/tdb2/solver/OpExecutorTDB2.java
+++ b/jena-tdb2/src/main/java/org/apache/jena/tdb2/solver/OpExecutorTDB2.java
@@ -27,7 +27,6 @@ import org.apache.jena.atlas.lib.tuple.Tuple;
 import org.apache.jena.atlas.logging.Log;
 import org.apache.jena.graph.Graph;
 import org.apache.jena.graph.Node;
-import org.apache.jena.sparql.ARQInternalErrorException;
 import org.apache.jena.sparql.algebra.Op;
 import org.apache.jena.sparql.algebra.op.*;
 import org.apache.jena.sparql.algebra.optimize.TransformFilterPlacement;
@@ -42,6 +41,7 @@ import org.apache.jena.sparql.engine.iterator.QueryIterPeek;
 import org.apache.jena.sparql.engine.main.OpExecutor;
 import org.apache.jena.sparql.engine.main.OpExecutorFactory;
 import org.apache.jena.sparql.engine.main.QC;
+import org.apache.jena.sparql.engine.main.StageGenerator;
 import org.apache.jena.sparql.engine.main.iterator.QueryIterGraph;
 import org.apache.jena.sparql.engine.optimizer.reorder.ReorderProc;
 import org.apache.jena.sparql.engine.optimizer.reorder.ReorderTransformation;
@@ -53,17 +53,17 @@ import org.apache.jena.tdb2.store.NodeId;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-/** TDB executor for algebra expressions.  It is the standard ARQ executor
- *  except for basic graph patterns and filtered basic graph patterns 
(currently).
+/**
+ * TDB2 executor for algebra expressions.  It is the standard ARQ executor
+ * except for basic graph patterns and filtered basic graph patterns 
(currently).
  *
- * See also: StageGeneratorDirectTDB, a non-reordering
+ * See also: {@link StageGeneratorDirectTDB}, a non-reordering {@link 
StageGenerator}
  */
 public class OpExecutorTDB2 extends OpExecutor
 {
     private static final Logger log = 
LoggerFactory.getLogger(OpExecutorTDB2.class);
 
-    public final static OpExecutorFactory OpExecFactoryTDB = new 
OpExecutorFactory()
-    {
+    public final static OpExecutorFactory OpExecFactoryTDB = new 
OpExecutorFactory() {
         @Override
         public OpExecutor create(ExecutionContext execCxt)
         { return new OpExecutorTDB2(execCxt); }
@@ -73,8 +73,7 @@ public class OpExecutorTDB2 extends OpExecutor
 
     // A new compile object is created for each op compilation.
     // So the execCxt is changing as we go through the query-compile-execute 
process
-    public OpExecutorTDB2(ExecutionContext execCxt)
-    {
+    public OpExecutorTDB2(ExecutionContext execCxt) {
         super(execCxt);
         // NB. The dataset may be a TDB one, or a general one.
         // Any merged union graph magic (for a TDB dataset was handled
@@ -96,29 +95,22 @@ public class OpExecutorTDB2 extends OpExecutor
     // Need to work with SolverLib which wraps the NodeId bindgins with a 
converter.
 
     @Override
-    protected QueryIterator execute(OpDistinct opDistinct, QueryIterator input)
-    {
+    protected QueryIterator execute(OpDistinct opDistinct, QueryIterator 
input) {
         return super.execute(opDistinct, input);
     }
 
     @Override
-    protected QueryIterator execute(OpReduced opReduced, QueryIterator input)
-    {
+    protected QueryIterator execute(OpReduced opReduced, QueryIterator input) {
         return super.execute(opReduced, input);
     }
 
     @Override
-    protected QueryIterator execute(OpFilter opFilter, QueryIterator input)
-    {
+    protected QueryIterator execute(OpFilter opFilter, QueryIterator input) {
         if ( ! isForTDB )
             return super.execute(opFilter, input);
 
-        // If the filter does not apply to the input??
-        // Where does ARQ catch this?
-
         // (filter (bgp ...))
-        if ( OpBGP.isBGP(opFilter.getSubOp()) )
-        {
+        if ( OpBGP.isBGP(opFilter.getSubOp()) ) {
             // Still may be a TDB graph in a non-TDB dataset (e.g. a named 
model)
             GraphTDB graph = (GraphTDB)execCxt.getActiveGraph();
             OpBGP opBGP = (OpBGP)opFilter.getSubOp();
@@ -126,8 +118,7 @@ public class OpExecutorTDB2 extends OpExecutor
         }
 
         // (filter (quadpattern ...))
-        if ( opFilter.getSubOp() instanceof OpQuadPattern quadPattern)
-        {
+        if ( opFilter.getSubOp() instanceof OpQuadPattern quadPattern) {
             DatasetGraphTDB ds = (DatasetGraphTDB)execCxt.getDataset();
             return optimizeExecuteQuads(ds, input,
                                         quadPattern.getGraphNode(), 
quadPattern.getBasicPattern(),
@@ -136,31 +127,23 @@ public class OpExecutorTDB2 extends OpExecutor
 
         // (filter (anything else))
         return super.execute(opFilter, input);
-        }
+    }
 
     // ---- Triple patterns
 
     @Override
-    protected QueryIterator execute(OpBGP opBGP, QueryIterator input)
-    {
+    protected QueryIterator execute(OpBGP opBGP, QueryIterator input) {
         if ( ! isForTDB )
             return super.execute(opBGP, input);
 
         GraphTDB graph = (GraphTDB)execCxt.getActiveGraph();
         return executeBGP(graph, opBGP, input, null, execCxt);
-
     }
 
     @Override
-    protected QueryIterator execute(OpQuadPattern quadPattern, QueryIterator 
input)
-    {
+    protected QueryIterator execute(OpQuadPattern quadPattern, QueryIterator 
input) {
         if ( ! isForTDB )
             return super.execute(quadPattern, input);
-
-    //        DatasetGraph dg = execCxt.getDataset();
-    //        if ( ! ( dg instanceof DatasetGraphTDB ) )
-    //            throw new InternalErrorException("Not a TDB backed dataset 
in quad pattern execution");
-
         DatasetGraphTDB ds = (DatasetGraphTDB)execCxt.getDataset();
         BasicPattern bgp = quadPattern.getBasicPattern();
         Node gn = quadPattern.getGraphNode();
@@ -168,20 +151,17 @@ public class OpExecutorTDB2 extends OpExecutor
     }
 
     @Override
-    protected QueryIterator execute(OpGraph opGraph, QueryIterator input)
-    {
+    protected QueryIterator execute(OpGraph opGraph, QueryIterator input) {
         // Path evaluation or dataset sets which do not go straight to the 
DatasetGraphTDB
         return new QueryIterGraph(input, opGraph, execCxt);
     }
 
     /** Execute a BGP (and filters) on a TDB graph, which may be in default 
storage or it may be a named graph */
-    private static QueryIterator executeBGP(GraphTDB graph, OpBGP opBGP, 
QueryIterator input, ExprList exprs,
-                                            ExecutionContext execCxt)
-    {
+    private static QueryIterator executeBGP(GraphTDB graph, OpBGP opBGP, 
QueryIterator input,
+                                            ExprList exprs, ExecutionContext 
execCxt) {
         DatasetGraphTDB dsgtdb = graph.getDSG();
         // Is it the real default graph (normal route or explicitly named)?
-        if ( ! isDefaultGraphStorage(graph.getGraphName()))
-        {
+        if ( !isDefaultGraphStorage(graph.getGraphName()) ) {
             // Not default storage - it's a named graph in storage.
             return optimizeExecuteQuads(dsgtdb, input, graph.getGraphName(), 
opBGP.getPattern(), exprs, execCxt);
         }
@@ -192,41 +172,36 @@ public class OpExecutorTDB2 extends OpExecutor
 
     /** Execute, with optimization, a basic graph pattern on the default graph 
storage */
     private static QueryIterator optimizeExecuteTriples(DatasetGraphTDB 
dsgtdb, QueryIterator input,
-                                                        BasicPattern pattern, 
ExprList exprs,
-                                                        ExecutionContext 
execCxt)
+                                                        BasicPattern pattern, 
ExprList exprs, ExecutionContext execCxt)
     {
-        // -- Input
-        // Must pass this iterator into the next stage.
-        if ( pattern.size() >= 2 ) {
-            // Must be 2 or triples to reorder.
-            ReorderTransformation transform = dsgtdb.getReorderTransform();
-            if ( transform != null ) {
-                QueryIterPeek peek = QueryIterPeek.create(input, execCxt);
-                input = peek; // Must pass on
-                try {
+        try {
+            if ( ! input.hasNext() )
+                return input;
+
+            // -- Input
+            // Must pass this iterator into the next stage.
+            if ( pattern.size() >= 2 ) {
+                // Must be 2 or triples to reorder.
+                ReorderTransformation transform = dsgtdb.getReorderTransform();
+                if ( transform != null ) {
+                    QueryIterPeek peek = QueryIterPeek.create(input, execCxt);
+                    input = peek; // Must pass on
                     pattern = reorder(pattern, peek, transform);
-                } catch (Exception e) {
-                    return new QueryIterFailed(input, execCxt, e);
                 }
             }
-        } else {
-            try {
-                if ( !input.hasNext() )
-                    return input;
-            } catch (Exception e) {
-                return new QueryIterFailed(input, execCxt, e);
+
+            if ( exprs == null ) {
+                Explain.explain("Execute", pattern, execCxt.getContext());
+                Predicate<Tuple<NodeId>> filter = 
QC2.getFilter(execCxt.getContext());
+                return PatternMatchTDB2.execute(dsgtdb, 
Quad.defaultGraphNodeGenerated, pattern, input, filter, execCxt);
             }
-        }
+            // -- Filter placement
 
-        if ( exprs == null ) {
-            Explain.explain("Execute", pattern, execCxt.getContext());
-            Predicate<Tuple<NodeId>> filter = 
QC2.getFilter(execCxt.getContext());
-            return PatternMatchTDB2.execute(dsgtdb, 
Quad.defaultGraphNodeGenerated, pattern, input, filter, execCxt);
+            Op op = TransformFilterPlacement.transform(exprs, pattern);
+            return plainExecute(op, input, execCxt);
+        } catch (Exception e) {
+            return new QueryIterFailed(input, execCxt, e);
         }
-        // -- Filter placement
-
-        Op op = TransformFilterPlacement.transform(exprs, pattern);
-        return plainExecute(op, input, execCxt);
     }
 
     /** Execute, with optimization, a quad pattern */
@@ -236,48 +211,44 @@ public class OpExecutorTDB2 extends OpExecutor
                                                       ExprList exprs, 
ExecutionContext execCxt)
     {
         // ---- Graph names with special meaning.
-
         gn = decideGraphNode(gn, execCxt);
         if ( gn == null )
             return optimizeExecuteTriples(dsgtdb, input, bgp, exprs, execCxt);
+        try {
+            if ( ! input.hasNext() )
+                return input;
 
-        // ---- Execute quads+filters
-        if ( bgp.size() >= 2 ) {
-            ReorderTransformation transform = dsgtdb.getReorderTransform();
+            // ---- Execute quads+filters
+            if ( bgp.size() >= 2 ) {
+                ReorderTransformation transform = dsgtdb.getReorderTransform();
 
-            if ( transform != null ) {
-                QueryIterPeek peek = QueryIterPeek.create(input, execCxt);
-                input = peek; // Original input now invalid.
-                try {
+                if ( transform != null ) {
+                    QueryIterPeek peek = QueryIterPeek.create(input, execCxt);
+                    input = peek; // Original input now invalid.
                     bgp = reorder(bgp, peek, transform);
-                } catch (Exception e) {
-                    return new QueryIterFailed(input, execCxt, e);
                 }
             }
-        } else {
-            try {
-                if ( !input.hasNext() )
-                    return input;
-            } catch (Exception e) {
-                return new QueryIterFailed(input, execCxt, e);
+
+            if ( exprs == null ) {
+                // Triple-backed (but may be named as explicit default graph).
+                Explain.explain("Execute", bgp, execCxt.getContext());
+                Predicate<Tuple<NodeId>> filter = 
QC2.getFilter(execCxt.getContext());
+                return PatternMatchTDB2.execute(dsgtdb, gn, bgp, input, 
filter, execCxt);
             }
-        }
 
-        if ( exprs == null ) {
-            // Triple-backed (but may be named as explicit default graph).
-            Explain.explain("Execute", bgp, execCxt.getContext());
-            Predicate<Tuple<NodeId>> filter = 
QC2.getFilter(execCxt.getContext());
-            return PatternMatchTDB2.execute(dsgtdb, gn, bgp, input, filter, 
execCxt);
+            // -- Filter placement
+            Op op = TransformFilterPlacement.transform(exprs, gn, bgp);
+            return plainExecute(op, input, execCxt);
+        } catch (Exception e) {
+            return new QueryIterFailed(input, execCxt, e);
         }
-
-        // -- Filter placement
-        Op op = TransformFilterPlacement.transform(exprs, gn, bgp);
-        return plainExecute(op, input, execCxt);
     }
 
-    /** Execute without modification of the op - does <b>not</b> apply special 
graph name translations */
-    private static QueryIterator plainExecute(Op op, QueryIterator input, 
ExecutionContext execCxt)
-    {
+    /**
+     * Execute without modification of the op - does <b>not</b> apply special 
graph
+     * name translations
+     */
+    private static QueryIterator plainExecute(Op op, QueryIterator input, 
ExecutionContext execCxt) {
         // -- Execute
         // Switch to a non-reordering executor
         // The Op may be a sequence due to TransformFilterPlacement
@@ -293,43 +264,37 @@ public class OpExecutorTDB2 extends OpExecutor
         return QC.execute(op, input, ec2);
     }
 
-    private static BasicPattern reorder(BasicPattern pattern, QueryIterPeek 
peek, ReorderTransformation transform)
-    {
-        if ( transform != null )
-        {
+    private static BasicPattern reorder(BasicPattern pattern, QueryIterPeek 
peek, ReorderTransformation transform) {
+        // Caller tested that peek.hasNext is true.
+        if ( transform != null ) {
             // This works by getting one result from the peek iterator,
-            // and creating the more gounded BGP. The tranform is used to
+            // and creating the more grounded BGP. The transform is used to
             // determine the best order and the transformation is returned. 
This
             // transform is applied to the unsubstituted pattern (which will be
             // substituted as part of evaluation.
 
-            if ( ! peek.hasNext() )
-                throw new ARQInternalErrorException("Peek iterator is already 
empty");
-
-            BasicPattern pattern2 = Substitute.substitute(pattern, peek.peek() 
);
+            BasicPattern pattern2 = Substitute.substitute(pattern, 
peek.peek());
             // Calculate the reordering based on the substituted pattern.
             ReorderProc proc = transform.reorderIndexes(pattern2);
-            // Then reorder original patten
+            // Then reorder original pattern
             pattern = proc.reorder(pattern);
         }
         return pattern;
     }
 
-    /** Handle special graph node names.
-     * Returns null for default graph in storage (use the triple table).
-     * Returns Node.ANY for the union graph
+    /**
+     * Handle special graph node names. Returns null for default graph in 
storage
+     * (use the triple table). Returns Node.ANY for the union graph
      */
-    public static Node decideGraphNode(Node gn, ExecutionContext execCxt)
-    {
-     // ---- Graph names with special meaning.
+    public static Node decideGraphNode(Node gn, ExecutionContext execCxt) {
+        // ---- Graph names with special meaning.
 
         // Graph names with special meaning:
-        //   Quad.defaultGraphIRI -- the IRI used in GRAPH <> to mean the 
default graph.
-        //   Quad.defaultGraphNodeGenerated -- the internal marker node used 
for the quad form of queries.
-        //   Quad.unionGraph -- the IRI used in GRAPH <> to mean the union of 
named graphs
+        // * Quad.defaultGraphIRI -- the IRI used in GRAPH <> to mean the 
default graph.
+        // * Quad.defaultGraphNodeGenerated -- the internal marker node used 
for the quad form of queries.
+        // * Quad.unionGraph -- the IRI used in GRAPH <> to mean the union of 
named graphs
 
-        if ( isDefaultGraphStorage(gn) )
-        {
+        if ( isDefaultGraphStorage(gn) ) {
             // Storage concrete, default graph.
             // Either outside GRAPH (no implicit union)
             // or using the "name" of the default graph
@@ -347,8 +312,7 @@ public class OpExecutorTDB2 extends OpExecutor
     }
 
     // Is this a query against the real default graph in the storage (in a 
3-tuple table).
-    private static boolean isDefaultGraphStorage(Node gn)
-    {
+    private static boolean isDefaultGraphStorage(Node gn) {
         if ( gn == null )
             return true;
 
@@ -362,8 +326,7 @@ public class OpExecutorTDB2 extends OpExecutor
     }
 
     @Override
-    protected QueryIterator execute(OpDatasetNames dsNames, QueryIterator 
input)
-    {
+    protected QueryIterator execute(OpDatasetNames dsNames, QueryIterator 
input) {
         DatasetGraphTDB ds = (DatasetGraphTDB)execCxt.getDataset();
         Predicate<Tuple<NodeId>> filter = QC2.getFilter(execCxt.getContext());
         Node gn = dsNames.getGraphNode();
@@ -376,64 +339,58 @@ public class OpExecutorTDB2 extends OpExecutor
     // ---- OpExecute factories and plain executor.
 
     private static OpExecutorFactory plainFactory = new 
OpExecutorPlainFactoryTDB();
-    private static class OpExecutorPlainFactoryTDB implements OpExecutorFactory
-    {
+    private static class OpExecutorPlainFactoryTDB implements 
OpExecutorFactory {
         @Override
-        public OpExecutor create(ExecutionContext execCxt)
-        {
+        public OpExecutor create(ExecutionContext execCxt) {
             return new OpExecutorPlainTDB(execCxt);
         }
     }
 
-    /** An op executor that simply executes a BGP or QuadPattern without any 
reordering */
-    private static class OpExecutorPlainTDB extends OpExecutor
-    {
+    /**
+     * An op executor that simply executes a BGP or QuadPattern without any
+     * reordering
+     */
+    private static class OpExecutorPlainTDB extends OpExecutor {
         Predicate<Tuple<NodeId>> filter = null;
 
-        public OpExecutorPlainTDB(ExecutionContext execCxt)
-        {
+        public OpExecutorPlainTDB(ExecutionContext execCxt) {
             super(execCxt);
             filter = QC2.getFilter(execCxt.getContext());
         }
 
         @Override
-        public QueryIterator execute(OpBGP opBGP, QueryIterator input)
-        {
+        public QueryIterator execute(OpBGP opBGP, QueryIterator input) {
             Graph g = execCxt.getActiveGraph();
 
-            if ( g instanceof GraphTDB gtdb )
-            {
+            if ( g instanceof GraphTDB gtdb ) {
                 BasicPattern bgp = opBGP.getPattern();
                 Explain.explain("Execute", bgp, execCxt.getContext());
                 // Triple-backed (but may be named as explicit default graph).
                 Node gn = decideGraphNode(gtdb.getGraphName(), execCxt);
                 return PatternMatchTDB2.execute(gtdb.getDSG(), gn, bgp, input, 
filter, execCxt);
             }
-            Log.warn(this, "Non-GraphTDB passed to OpExecutorPlainTDB: 
"+g.getClass().getSimpleName());
+            Log.warn(this, "Non-GraphTDB passed to OpExecutorPlainTDB: " + 
g.getClass().getSimpleName());
             return super.execute(opBGP, input);
         }
 
         @Override
-        public QueryIterator execute(OpQuadPattern opQuadPattern, 
QueryIterator input)
-        {
+        public QueryIterator execute(OpQuadPattern opQuadPattern, 
QueryIterator input) {
             Node gn = opQuadPattern.getGraphNode();
             gn = decideGraphNode(gn, execCxt);
 
-            if ( execCxt.getDataset() instanceof DatasetGraphTDB dsgtdb )
-            {
+            if ( execCxt.getDataset() instanceof DatasetGraphTDB dsgtdb ) {
                 Explain.explain("Execute", opQuadPattern.getPattern(), 
execCxt.getContext());
                 BasicPattern bgp = opQuadPattern.getBasicPattern();
                 return PatternMatchTDB2.execute(dsgtdb, gn, bgp, input, 
filter, execCxt);
             }
             // Maybe a TDB named graph inside a non-TDB dataset.
             Graph g = execCxt.getActiveGraph();
-            if ( g instanceof GraphTDB gtdb )
-            {
-                // Triples graph from TDB (which is the default graph of the 
dataset),
+            if ( g instanceof GraphTDB gtdb ) {
+                // Triples graph from TDB, which is the default graph of the 
dataset,
                 // used a named graph in a composite dataset.
                 BasicPattern bgp = opQuadPattern.getBasicPattern();
                 Explain.explain("Execute", bgp, execCxt.getContext());
-                // Don't pass in G -- gn may be different.
+                // Don't pass in g -- gn may be different.
                 return PatternMatchTDB2.execute(gtdb.getDSG(), gn, bgp, input, 
filter, execCxt);
             }
             Log.warn(this, "Non-DatasetGraphTDB passed to OpExecutorPlainTDB");
diff --git 
a/jena-tdb2/src/main/java/org/apache/jena/tdb2/solver/StageGeneratorDirectTDB.java
 
b/jena-tdb2/src/main/java/org/apache/jena/tdb2/solver/StageGeneratorDirectTDB.java
index 2e5605da03..709148ff35 100644
--- 
a/jena-tdb2/src/main/java/org/apache/jena/tdb2/solver/StageGeneratorDirectTDB.java
+++ 
b/jena-tdb2/src/main/java/org/apache/jena/tdb2/solver/StageGeneratorDirectTDB.java
@@ -34,7 +34,7 @@ import org.apache.jena.tdb2.store.GraphViewSwitchable;
 import org.apache.jena.tdb2.store.NodeId;
 
 /**
- * Execute TDB requests directly -- no reordering Using OpExecutor is 
preferred.
+ * Execute TDB requests directly -- no reordering. Using OpExecutor is 
preferred.
  */
 public class StageGeneratorDirectTDB implements StageGenerator {
     // Using OpExecutor is preferred.
diff --git 
a/jena-tdb2/src/test/java/org/apache/jena/tdb2/store/Test_SPARQL_TDB.java 
b/jena-tdb2/src/test/java/org/apache/jena/tdb2/store/Test_SPARQL_TDB.java
index 2374295b22..fd9fc01f3d 100644
--- a/jena-tdb2/src/test/java/org/apache/jena/tdb2/store/Test_SPARQL_TDB.java
+++ b/jena-tdb2/src/test/java/org/apache/jena/tdb2/store/Test_SPARQL_TDB.java
@@ -32,8 +32,13 @@ import org.apache.jena.graph.NodeFactory;
 import org.apache.jena.graph.Triple;
 import org.apache.jena.query.*;
 import org.apache.jena.rdf.model.Model;
+import org.apache.jena.sparql.core.DatasetGraph;
+import org.apache.jena.sparql.exec.QueryExec;
+import org.apache.jena.sparql.exec.RowSet;
+import org.apache.jena.sparql.exec.RowSetOps;
 import org.apache.jena.sparql.sse.SSE;
 import org.apache.jena.system.Txn;
+import org.apache.jena.tdb2.DatabaseMgr;
 import org.apache.jena.tdb2.TDB2;
 import org.apache.jena.tdb2.TDB2Factory;
 import org.apache.jena.update.*;
@@ -41,8 +46,7 @@ import org.apache.jena.update.*;
 /**
  * Test SPARQL
  */
-public class Test_SPARQL_TDB
-{
+public class Test_SPARQL_TDB {
     private static Dataset create() {
         return TDB2Factory.createDataset();
     }
@@ -55,12 +59,13 @@ public class Test_SPARQL_TDB
     private static Triple triple = SSE.parseTriple("(<x> <y> 123)");
 
     // Standalone graph.
-    @Test public void sparql1()
-    {
-        // Test OpExecutor.execute(OpBGP) for a named graph used as a 
standalone model
+    @Test
+    public void sparql1() {
+        // Test OpExecutor.execute(OpBGP) for a named graph used as a 
standalone
+        // model
         Dataset ds = create();
         add(ds, graphName, triple);
-        Txn.executeRead(ds, ()->{
+        Txn.executeRead(ds, () -> {
             Model m = ds.getNamedModel(graphName);
             String qs = "SELECT * { ?s ?p ?o . }";
             Query query = QueryFactory.create(qs);
@@ -71,17 +76,18 @@ public class Test_SPARQL_TDB
     }
 
     // Standalone graph.
-    @Test public void sparql2()
-    {
-        // Test OpExecutor.execute(OpFilter)for a named graph used as a 
standalone model
+    @Test
+    public void sparql2() {
+        // Test OpExecutor.execute(OpFilter)for a named graph used as a 
standalone
+        // model
         Dataset ds = create();
         add(ds, graphName, triple);
 
-        Txn.executeRead(ds, ()->{
+        Txn.executeRead(ds, () -> {
             Model m = ds.getNamedModel(graphName);
             String qs = "SELECT * { ?s ?p ?o . FILTER ( ?o < 456 ) }";
             Query query = QueryFactory.create(qs);
-            try(QueryExecution qexec = QueryExecutionFactory.create(query, m)) 
{
+            try (QueryExecution qexec = QueryExecutionFactory.create(query, 
m)) {
                 ResultSet rs = qexec.execSelect();
                 ResultSetFormatter.consume(rs);
             }
@@ -89,11 +95,11 @@ public class Test_SPARQL_TDB
     }
 
     // Requires OpDatasetNames
-    @Test public void sparql3()
-    {
+    @Test
+    public void sparql3() {
         Dataset dataset = create();
         // No triple added
-        Txn.executeRead(dataset, ()->{
+        Txn.executeRead(dataset, () -> {
             Query query = QueryFactory.create("SELECT ?g { GRAPH ?g {} }");
             QueryExecution qExec = QueryExecutionFactory.create(query, 
dataset);
             ResultSet rs = qExec.execSelect();
@@ -102,11 +108,11 @@ public class Test_SPARQL_TDB
         });
     }
 
-    @Test public void sparql4()
-    {
+    @Test
+    public void sparql4() {
         Dataset dataset = create();
         add(dataset, graphName, triple);
-        Txn.executeRead(dataset, ()->{
+        Txn.executeRead(dataset, () -> {
             Query query = QueryFactory.create("SELECT ?g { GRAPH ?g {} }");
             QueryExecution qExec = QueryExecutionFactory.create(query, 
dataset);
             ResultSet rs = qExec.execSelect();
@@ -115,30 +121,44 @@ public class Test_SPARQL_TDB
         });
     }
 
-    @Test public void sparql5()
-    {
+    @Test
+    public void sparql5() {
         Dataset dataset = create();
         add(dataset, graphName, triple);
-        Txn.executeRead(dataset, ()->{
-            Query query = QueryFactory.create("ASK { GRAPH <"+graphName+"> {} 
}");
+        Txn.executeRead(dataset, () -> {
+            Query query = QueryFactory.create("ASK { GRAPH <" + graphName + "> 
{} }");
             boolean b = QueryExecutionFactory.create(query, dataset).execAsk();
             assertEquals(true, b);
         });
     }
 
-    @Test public void sparql6()
-    {
+    @Test
+    public void sparql6() {
         Dataset dataset = create();
         add(dataset, graphName, triple);
-        Txn.executeRead(dataset, ()->{
+        Txn.executeRead(dataset, () -> {
             Query query = QueryFactory.create("ASK { GRAPH <http://example/x> 
{} }");
             boolean b = QueryExecutionFactory.create(query, dataset).execAsk();
             assertEquals(false, b);
         });
     }
 
+    @Test
+    public void sparql7() {
+        // https://github.com/apache/jena/issues/3751
+        String qs = """
+                PREFIX : <http://example/>
+                SELECT * { ?x :property+ ?y . ?z :q1 123 . ?z :q2 456 . }
+                """;
+        DatasetGraph dsg = DatabaseMgr.createDatasetGraph();
+        dsg.executeRead(()->{
+            RowSet rs = QueryExec.dataset(dsg).query(qs).select();
+            RowSetOps.consume(rs);
+        });
+    }
+
     private static void add(Dataset dataset, String graphName, Triple triple) {
-        Txn.executeWrite(dataset, ()->{
+        Txn.executeWrite(dataset, () -> {
             Graph g2 = 
dataset.asDatasetGraph().getGraph(NodeFactory.createURI(graphName));
             g2.add(triple);
         });
@@ -146,10 +166,10 @@ public class Test_SPARQL_TDB
 
     // Test transactions effective.
 
-    @Test public void sparql_txn_1()
-    {
+    @Test
+    public void sparql_txn_1() {
         Dataset dataset = create();
-        Txn.executeWrite(dataset, ()->{
+        Txn.executeWrite(dataset, () -> {
             update(dataset, "INSERT DATA { <x:s> <x:p> <x:o> }");
         });
         // Explicit trasnaction steps.
@@ -159,56 +179,55 @@ public class Test_SPARQL_TDB
             assertEquals(1, n);
             n = count(dataset, "SELECT * { <x:s> <x:p> <x:o>}");
             assertEquals(1, n);
-        } finally { dataset.end(); }
+        } finally {
+            dataset.end();
+        }
     }
 
-    @Test public void sparql_txn_2()
-    {
+    @Test
+    public void sparql_txn_2() {
         Dataset dataset1 = create(Location.mem("foo"));
         Dataset dataset2 = create(Location.mem("foo"));
 
-        Txn.executeWrite(dataset1, ()->{
+        Txn.executeWrite(dataset1, () -> {
             update(dataset1, "INSERT DATA { <x:s> <x:p> <x:o> }");
         });
 
-        Txn.executeRead(dataset1, ()->{
+        Txn.executeRead(dataset1, () -> {
             assertEquals(1, count(dataset1));
         });
 
         // Same location.
-        Txn.executeRead(dataset2, ()->{
+        Txn.executeRead(dataset2, () -> {
             assertEquals(1, count(dataset2));
         });
     }
 
-    @Test public void sparql_update_unionGraph()
-    {
+    @Test
+    public void sparql_update_unionGraph() {
         Dataset ds = TDB2Factory.createDataset();
         // Update concrete default graph
-        Txn.executeWrite(ds, ()->{
+        Txn.executeWrite(ds, () -> {
             ds.asDatasetGraph().add(SSE.parseQuad("(<g> <s> <p> 123)"));
         });
         ds.getContext().setTrue(TDB2.symUnionDefaultGraph);
 
-        Txn.executeWrite(ds, ()->{
+        Txn.executeWrite(ds, () -> {
             // Update by looking in union graph
-            String us = StrUtils.strjoinNL(
-                "INSERT { GRAPH <http://example/g2> { ?s ?p 'NEW' } }",
-                "WHERE { ",
-                     "?s ?p 123",
-                " }" );
+            String us = StrUtils.strjoinNL("INSERT { GRAPH <http://example/g2> 
{ ?s ?p 'NEW' } }", "WHERE { ", "?s ?p 123", " }");
             UpdateRequest req = UpdateFactory.create(us);
             UpdateAction.execute(req, ds);
         });
 
-        Txn.executeRead(ds, ()->{
+        Txn.executeRead(ds, () -> {
             Model m = ds.getNamedModel("http://example/g2";);
-            assertEquals(1, m.size(), ()->"Did not find 1 statement in named 
graph");
+            assertEquals(1, m.size(), () -> "Did not find 1 statement in named 
graph");
         });
     }
 
-    private int count(Dataset dataset)
-    { return count(dataset, "SELECT * { ?s ?p ?o }"); }
+    private int count(Dataset dataset) {
+        return count(dataset, "SELECT * { ?s ?p ?o }");
+    }
 
     private int count(Dataset dataset, String queryString)
 
@@ -218,8 +237,8 @@ public class Test_SPARQL_TDB
         ResultSet rs = qExec.execSelect();
         return ResultSetFormatter.consume(rs);
     }
-    private void update(Dataset dataset, String string)
-    {
+
+    private void update(Dataset dataset, String string) {
         UpdateRequest req = UpdateFactory.create(string);
         UpdateExecution proc = UpdateExecutionFactory.create(req, dataset);
         proc.execute();

Reply via email to