From 853f6308953c0734747e431f0ed5be9b8b65eca7 Mon Sep 17 00:00:00 2001 From: mini666 Date: Fri, 27 Mar 2026 10:51:02 +0900 Subject: [PATCH 1/4] HBASE-30033 Scan.setFilter() should validate against existing batch setting Scan.setBatch() validates that the scan does not have a filter with hasFilterRow()=true. However, Scan.setFilter() does not perform the reverse check. This allows creating an invalid Scan by calling setBatch() before setFilter(), bypassing the validation that setBatch() was designed to enforce. Added validation in setFilter() to throw IncompatibleFilterException when a filter with hasFilterRow()=true is set on a scan that already has batch configured. --- .../src/main/java/org/apache/hadoop/hbase/client/Scan.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/Scan.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/Scan.java index 5cc0d0fac87f..630edc4a6ffd 100644 --- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/Scan.java +++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/Scan.java @@ -554,6 +554,10 @@ public Scan setMaxResultSize(long maxResultSize) { @Override public Scan setFilter(Filter filter) { + if (filter != null && filter.hasFilterRow() && this.batch > 0) { + throw new IncompatibleFilterException( + "Cannot set a filter that returns true for filter.hasFilterRow on a scan with batch set"); + } super.setFilter(filter); return this; } From a49a095980680344d6a8a6d41d84db7484c37d9f Mon Sep 17 00:00:00 2001 From: mini666 Date: Fri, 27 Mar 2026 12:34:36 +0900 Subject: [PATCH 2/4] HBASE-30033 Add tests for setFilter() batch validation - testSetFilterWithBatchThrows: setBatch() then setFilter(PageFilter) should throw IncompatibleFilterException - testSetFilterWithoutBatchDoesNotThrow: setFilter(PageFilter) without batch should succeed - testSetFilterWithBatchAndNonFilterRowFilter: setBatch() then setFilter(FilterList) should succeed since FilterList.hasFilterRow() returns false --- .../apache/hadoop/hbase/client/TestScan.java | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/hbase-client/src/test/java/org/apache/hadoop/hbase/client/TestScan.java b/hbase-client/src/test/java/org/apache/hadoop/hbase/client/TestScan.java index dcc624ff112b..a0a0bf691ed4 100644 --- a/hbase-client/src/test/java/org/apache/hadoop/hbase/client/TestScan.java +++ b/hbase-client/src/test/java/org/apache/hadoop/hbase/client/TestScan.java @@ -29,6 +29,8 @@ import org.apache.hadoop.hbase.HConstants; import org.apache.hadoop.hbase.client.Scan.ReadType; import org.apache.hadoop.hbase.filter.FilterList; +import org.apache.hadoop.hbase.filter.IncompatibleFilterException; +import org.apache.hadoop.hbase.filter.PageFilter; import org.apache.hadoop.hbase.security.access.Permission; import org.apache.hadoop.hbase.security.visibility.Authorizations; import org.apache.hadoop.hbase.testclassification.ClientTests; @@ -254,6 +256,28 @@ public void testScanCopyConstructor() throws Exception { "Make sure copy constructor adds all the fields in the copied object"); } + @Test(expected = IncompatibleFilterException.class) + public void testSetFilterWithBatchThrows() { + Scan scan = new Scan(); + scan.setBatch(5); + scan.setFilter(new PageFilter(10)); + } + + @Test + public void testSetFilterWithoutBatchDoesNotThrow() { + Scan scan = new Scan(); + scan.setFilter(new PageFilter(10)); + // no exception expected + } + + @Test + public void testSetFilterWithBatchAndNonFilterRowFilter() { + Scan scan = new Scan(); + scan.setBatch(5); + scan.setFilter(new FilterList()); + // FilterList.hasFilterRow() returns false, so no exception expected + } + @Test public void testScanReadType() throws Exception { Scan scan = new Scan(); From daef05b6e7a87bf92ddab9ccba1a1a2e28b7d5b7 Mon Sep 17 00:00:00 2001 From: juke-mini666 Date: Fri, 27 Mar 2026 14:51:03 +0900 Subject: [PATCH 3/4] HBASE-30033 Add test for setFilter(null) with batch set --- .../java/org/apache/hadoop/hbase/client/TestScan.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/hbase-client/src/test/java/org/apache/hadoop/hbase/client/TestScan.java b/hbase-client/src/test/java/org/apache/hadoop/hbase/client/TestScan.java index a0a0bf691ed4..a44f5b91e62d 100644 --- a/hbase-client/src/test/java/org/apache/hadoop/hbase/client/TestScan.java +++ b/hbase-client/src/test/java/org/apache/hadoop/hbase/client/TestScan.java @@ -278,6 +278,14 @@ public void testSetFilterWithBatchAndNonFilterRowFilter() { // FilterList.hasFilterRow() returns false, so no exception expected } + @Test + public void testSetFilterWithBatchAndNullFilter() { + Scan scan = new Scan(); + scan.setBatch(5); + scan.setFilter(null); + // null filter should not throw + } + @Test public void testScanReadType() throws Exception { Scan scan = new Scan(); From 314b8af5fda58f4268506d4b3143aeadb1867412 Mon Sep 17 00:00:00 2001 From: juke-mini666 Date: Sat, 28 Mar 2026 07:46:45 +0900 Subject: [PATCH 4/4] HBASE-30033 Use assertThrows instead of @Test(expected) --- .../test/java/org/apache/hadoop/hbase/client/TestScan.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/hbase-client/src/test/java/org/apache/hadoop/hbase/client/TestScan.java b/hbase-client/src/test/java/org/apache/hadoop/hbase/client/TestScan.java index a44f5b91e62d..26ef4c0154f9 100644 --- a/hbase-client/src/test/java/org/apache/hadoop/hbase/client/TestScan.java +++ b/hbase-client/src/test/java/org/apache/hadoop/hbase/client/TestScan.java @@ -20,6 +20,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.fail; import java.io.IOException; @@ -256,11 +257,11 @@ public void testScanCopyConstructor() throws Exception { "Make sure copy constructor adds all the fields in the copied object"); } - @Test(expected = IncompatibleFilterException.class) + @Test public void testSetFilterWithBatchThrows() { Scan scan = new Scan(); scan.setBatch(5); - scan.setFilter(new PageFilter(10)); + assertThrows(IncompatibleFilterException.class, () -> scan.setFilter(new PageFilter(10))); } @Test