Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@
import static org.apache.geode.cache.Region.SEPARATOR;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import java.util.ArrayList;
import java.util.Collection;

import org.junit.After;
Expand Down Expand Up @@ -163,4 +165,58 @@ public void testIndexInfoOnLocalRegion() throws Exception {
assertEquals(results.size(), ((Integer) rslts).intValue());
}

/**
* Test for GEODE-10526: afterIndexLookup should handle null indexMap gracefully
*
* This test verifies that afterIndexLookup does not throw NullPointerException
* when the ThreadLocal indexMap has not been initialized. This can occur in
* partitioned region queries when afterIndexLookup is called without a
* corresponding beforeIndexLookup call, or when beforeIndexLookup fails
* before initializing the ThreadLocal.
*/
@Test
public void testAfterIndexLookupWithUninitializedThreadLocal() {
// Create a new IndexTrackingQueryObserver without initializing its ThreadLocal
IndexTrackingQueryObserver observer = new IndexTrackingQueryObserver();

// Create a mock result collection
Collection<Object> results = new ArrayList<>();
results.add(new Object());

try {
// Call afterIndexLookup without calling beforeIndexLookup first
// This simulates the scenario where the ThreadLocal is not initialized
// Before the fix, this would throw NullPointerException at line 110
observer.afterIndexLookup(results);

// If we reach here, the fix is working correctly
// The method should return gracefully when indexMap is null
} catch (NullPointerException e) {
fail("GEODE-10526: afterIndexLookup should not throw NullPointerException when "
+ "ThreadLocal is uninitialized. This indicates the null check is missing. "
+ "Exception: " + e.getMessage());
}
}

/**
* Test for GEODE-10526: afterIndexLookup should handle null results parameter
*
* Verify that the existing null check for results parameter still works.
*/
@Test
public void testAfterIndexLookupWithNullResults() {
IndexTrackingQueryObserver observer = new IndexTrackingQueryObserver();

try {
// Call afterIndexLookup with null results
// This should return early without any exceptions
observer.afterIndexLookup(null);

// Success - method handled null results correctly
} catch (Exception e) {
fail("afterIndexLookup should handle null results parameter gracefully. "
+ "Exception: " + e.getMessage());
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,15 @@ public void afterIndexLookup(Collection results) {
// append the size of the lookup results (and bucket id if its an Index on bucket)
// to IndexInfo results Map.
Map indexMap = (Map) indexInfo.get();

// Guard against uninitialized ThreadLocal in partitioned queries
if (indexMap == null) {
// beforeIndexLookup was not called or did not complete successfully.
// This can occur in partitioned region query execution across buckets
// when exceptions occur or when query execution paths bypass beforeIndexLookup.
return;
}

Index index = (Index) lastIndexUsed.get();
if (index != null) {
IndexInfo indexInfo = (IndexInfo) indexMap.get(getIndexName(index, lastKeyUsed.get()));
Expand Down
Loading