This is an automated email from the ASF dual-hosted git repository.

andy pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/jena.git


The following commit(s) were added to refs/heads/main by this push:
     new d560c7829d GH-3516: Removed needless multiHashProbleTable.clear() from 
AbstractIterHashJoin.close().
d560c7829d is described below

commit d560c7829dc3f8040325e9ac0dd9c5a7320e6c6c
Author: Claus Stadler <[email protected]>
AuthorDate: Fri Oct 17 13:24:54 2025 +0200

    GH-3516: Removed needless multiHashProbleTable.clear() from 
AbstractIterHashJoin.close().
---
 .../jena/sparql/engine/join/AbstractIterHashJoin.java    | 16 ++++++++++------
 .../org/apache/jena/sparql/engine/join/JoinIndex.java    | 15 +++++++++++++--
 .../jena/sparql/engine/join/MultiHashProbeTable.java     | 16 ++++++++--------
 .../jena/sparql/engine/join/AbstractTestInnerJoin.java   |  5 +++++
 4 files changed, 36 insertions(+), 16 deletions(-)

diff --git 
a/jena-arq/src/main/java/org/apache/jena/sparql/engine/join/AbstractIterHashJoin.java
 
b/jena-arq/src/main/java/org/apache/jena/sparql/engine/join/AbstractIterHashJoin.java
index 126be65a85..4da1392983 100644
--- 
a/jena-arq/src/main/java/org/apache/jena/sparql/engine/join/AbstractIterHashJoin.java
+++ 
b/jena-arq/src/main/java/org/apache/jena/sparql/engine/join/AbstractIterHashJoin.java
@@ -44,14 +44,16 @@ public abstract class AbstractIterHashJoin extends 
QueryIter2 {
     // See also stats in the probe table.
 
     protected JoinKey                   joinKey ;
-    protected MultiHashProbeTable       hashTable ;
+
+    // HashTable is initialized lazily.
+    protected MultiHashProbeTable       hashTable   = null ;
 
     private QueryIterator               iterStream ;
-    private Binding                     rowStream       = null ;
+    private Binding                     rowStream   = null ;
     private Iterator<Binding>           iterCurrent ;
     private boolean                     yielded ;       // Flag to note when 
current probe causes a result.
     // Hanlde any "post join" additions.
-    private Iterator<Binding>           iterTail        = null ;
+    private Iterator<Binding>           iterTail    = null ;
 
     enum Phase { INIT, HASH , STREAM, TRAILER, DONE }
     Phase state = Phase.INIT ;
@@ -234,13 +236,15 @@ public abstract class AbstractIterHashJoin extends 
QueryIter2 {
         if ( JoinLib.JOIN_EXPLAIN ) {
             String x = String.format(
                          "HashJoin: LHS=%d RHS=%d Results=%d Table=%s",
-                         s_countProbe, s_countScan, s_countResults,
-                         hashTable.toString()) ;
+                         s_countProbe, s_countScan, s_countResults, hashTable) 
;
             System.out.println(x) ;
         }
         // In case it's a peek iterator.
         iterStream.close() ;
-        hashTable.clear();
+        if ( hashTable != null ) {
+            hashTable.clear() ;
+            hashTable = null ;
+        }
     }
 
     @Override
diff --git 
a/jena-arq/src/main/java/org/apache/jena/sparql/engine/join/JoinIndex.java 
b/jena-arq/src/main/java/org/apache/jena/sparql/engine/join/JoinIndex.java
index e66d28ba94..0c80adefca 100644
--- a/jena-arq/src/main/java/org/apache/jena/sparql/engine/join/JoinIndex.java
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/engine/join/JoinIndex.java
@@ -41,14 +41,21 @@ import org.slf4j.LoggerFactory;
 
 /**
  * This class indexes a set of rows w.r.t. a join key, referred to as the 
<i>main join key</i>.
- * <p />
+ * <p>
  * Consider the main join key [?x, ?y, ?z]:
- * <p />
  * All rows that bind all three variables will be placed into the main table.
  *
+ * <p>
  * Any rows that only bind a sub set of the variables, such as [?x, ?z] or 
[?y],
  * are placed into respective skew tables.
  *
+ * <p>
+ * The super join determines the bit set representation of the the main and 
skew join keys.
+ * It and must declare at least all variables of the main join key.
+ * For example, given the super join key [?a, ?x, ?y, ?b ?z] the 
aforementioned main join key
+ * becomes represented with the bit pattern [0, 1, 1, 0, 1].
+ *
+ * <p>
  * JoinIndex instances are dynamically created by {@link MultiHashProbeTable} 
based on the
  * variables of the bindings used in lookup requests for matching rows.
  *
@@ -84,6 +91,10 @@ class JoinIndex
         this.mainTable = new HashProbeTable(mainJoinKey);
     }
 
+    public JoinKey getSuperJoinKey() {
+        return superJoinKey;
+    }
+
     public BitSet getMainJoinKeyBitSet() {
         return mainJoinKeyBitSet;
     }
diff --git 
a/jena-arq/src/main/java/org/apache/jena/sparql/engine/join/MultiHashProbeTable.java
 
b/jena-arq/src/main/java/org/apache/jena/sparql/engine/join/MultiHashProbeTable.java
index 0333854f94..41552ff496 100644
--- 
a/jena-arq/src/main/java/org/apache/jena/sparql/engine/join/MultiHashProbeTable.java
+++ 
b/jena-arq/src/main/java/org/apache/jena/sparql/engine/join/MultiHashProbeTable.java
@@ -69,7 +69,7 @@ class MultiHashProbeTable
     private final JoinIndex   initialIndex;
 
     /** Tables for hash lookups. Will be created dynamically during {@link 
#getCandidates(Binding)}. */
-    private final Map<BitSet, JoinIndex> indexes = new HashMap<>();
+    private final Map<BitSet, JoinIndex> indexes     = new HashMap<>();
 
     /** The set of seen variables across all rows */
     private final Set<Var>    seenVarSet             = new LinkedHashSet<>();
@@ -92,10 +92,6 @@ class MultiHashProbeTable
             initialJoinKey = JoinKey.empty();
         }
 
-        // If an initial join key is given then its variables are added to 
seen vars
-        // so that those correspond to the first bits of the bit keys
-        seenVarSet.addAll(initialJoinKey);
-
         int nbits = initialJoinKey.size();
         BitSet initialJoinKeyBitset = new BitSet(nbits);
         initialJoinKeyBitset.flip(0, nbits);
@@ -129,7 +125,7 @@ class MultiHashProbeTable
         initialIndex.put(row);
     }
 
-    /** Update seen vars with the row's relevant variables w.r.t. an optional 
rootJoinKey. */
+    /** Update seen vars with the row's relevant variables w.r.t. an optional 
maxJoinKey. */
     private void updateSeenVars(Binding row) {
         if (maxJoinKey == null) {
             row.vars().forEachRemaining(seenVarSet::add);
@@ -180,9 +176,13 @@ class MultiHashProbeTable
      *  This method is package private so that it can be called from tests.
      */
     void doFinalize() {
-        // Note: We need to stick with the variable order provided in the 
initial index -> don't sort!
+        // If an initial join key is given then its variables are prepended to 
seen vars
+        // so that those correspond to the first bits of the bit keys!
+        // This means we need to stick with the variable order provided in the 
initial index
+        // -> don't sort!
         // Arrays.sort(seenVars, (a, b) -> a.getName().compareTo(b.getName()));
-        seenVarsJoinKey = JoinKey.create(seenVarSet);
+        seenVarsJoinKey = JoinKey.newBuilder()
+            .addAll(initialIndex.getSuperJoinKey()).addAll(seenVarSet).build();
         indexes.put(initialIndex.getMainJoinKeyBitSet(), initialIndex);
         isFinalized = true;
     }
diff --git 
a/jena-arq/src/test/java/org/apache/jena/sparql/engine/join/AbstractTestInnerJoin.java
 
b/jena-arq/src/test/java/org/apache/jena/sparql/engine/join/AbstractTestInnerJoin.java
index 74ee491a31..ad5f4f7873 100644
--- 
a/jena-arq/src/test/java/org/apache/jena/sparql/engine/join/AbstractTestInnerJoin.java
+++ 
b/jena-arq/src/test/java/org/apache/jena/sparql/engine/join/AbstractTestInnerJoin.java
@@ -24,6 +24,7 @@ import org.junit.jupiter.api.Test;
 
 import org.apache.jena.sparql.algebra.Table;
 import org.apache.jena.sparql.core.Var;
+import org.apache.jena.sparql.engine.QueryIterator;
 import org.apache.jena.sparql.expr.ExprList;
 
 /** Tests for inner/equi joins */
@@ -80,6 +81,10 @@ public abstract class AbstractTestInnerJoin extends 
AbstractTestJoin {
     @Test public void join_skew_02b() { testJoin("w", tableS1b(), tableS2(), 
tableS1J2()); }
     @Test public void join_skew_03b() { testJoin(null, tableS1b(), tableS2(), 
tableS1J2()); }
 
+    @Test public void testCloseOfUnusedIterator() {
+        QueryIterator qIter = join(null, table1() , table1(), null);
+        qIter.close();
+    }
 
     @Test
     public void join_skew_04() {

Reply via email to