@@ -1346,39 +1346,6 @@ TEST_F(PageFilteredRowGroupReaderTest, BitmapAllAndPartialPagesMixed) {
13461346 }
13471347}
13481348
1349- // / Test: bitmap hits partial pages of a row group, with page-filtered option disabled.
1350- // /
1351- // / 200 rows, 10 rows per page, 100 rows per row group → 2 row groups.
1352- // / Bitmap: {120..149} hits pages 2-4 of RG1.
1353- // / Expected: 100 rows (100-199) because page-filtered option is disabled, so page-level bitmap is
1354- // / ignored.
1355- TEST_F (PageFilteredRowGroupReaderTest, BitmapWithPageFilteredOptionDisabled) {
1356- std::string file_name = dir_->Str () + " /bitmap_all_and_partial.parquet" ;
1357- auto data = MakeSequentialIntData (200 );
1358- WriteTestFile (file_name, data, /* write_batch_size=*/ 10 , /* max_row_group_length=*/ 100 );
1359-
1360- RoaringBitmap32 bitmap;
1361- bitmap.AddRange (120 , 150 ); // pages 2-4 of RG1
1362-
1363- auto read_schema = arrow::schema ({arrow::field (" val" , arrow::int32 ())});
1364- std::map<std::string, std::string> options;
1365- options[PARQUET_READ_ENABLE_PAGE_INDEX_FILTER ] = " false" ;
1366- std::shared_ptr<arrow::ChunkedArray> result;
1367- ReadWithPredicateAndBitmapImpl (file_name, read_schema, /* predicate=*/ nullptr , bitmap, &result,
1368- options);
1369- ASSERT_TRUE (result);
1370- ASSERT_EQ (100 , result->length ());
1371-
1372- // Verify: 100-199
1373- auto flat = arrow::Concatenate (result->chunks ()).ValueOrDie ();
1374- auto struct_arr = std::dynamic_pointer_cast<arrow::StructArray>(flat);
1375- ASSERT_TRUE (struct_arr);
1376- auto val_arr = std::dynamic_pointer_cast<arrow::Int32Array>(struct_arr->field (0 ));
1377- for (int32_t i = 0 ; i < 100 ; ++i) {
1378- ASSERT_EQ (100 + i, val_arr->Value (i));
1379- }
1380- }
1381-
13821349// / Test: bitmap + predicate both applied, bitmap hits all pages of some row groups.
13831350// /
13841351// / 200 rows, 10 rows per page, 100 rows per row group → 2 row groups.
@@ -1615,4 +1582,127 @@ TEST_F(PageFilteredRowGroupReaderTest, BitmapTrimStrategyTest) {
16151582 }
16161583}
16171584
1585+ // / Test: invalid strategy value returns Status::Invalid.
1586+ // /
1587+ // / 200 rows, 50 rows per page, 100 rows per row group → 2 row groups.
1588+ // / Bitmap: [0,10), [45, 50), [60, 70) — same as BitmapCoalesceTest.
1589+ // / Strategy: "invalid" (not one of "coalesce", "trim", "none").
1590+ // / Expected: SetReadSchema returns Status::Invalid.
1591+ TEST_F (PageFilteredRowGroupReaderTest, BitmapInvalidStrategyTest) {
1592+ std::string file_name = dir_->Str () + " /invalid_strategy.parquet" ;
1593+ auto data = MakeSequentialIntData (200 );
1594+ WriteTestFile (file_name, data, /* write_batch_size=*/ 50 , /* max_row_group_length=*/ 100 );
1595+
1596+ RoaringBitmap32 bitmap;
1597+ bitmap.AddRange (0 , 10 );
1598+ bitmap.AddRange (45 , 50 );
1599+ bitmap.AddRange (60 , 70 );
1600+
1601+ std::map<std::string, std::string> options;
1602+ options[PARQUET_READ_BITMAP_ROW_RANGE_REFINING_STRATEGY ] = " invalid" ;
1603+
1604+ ASSERT_OK_AND_ASSIGN (std::shared_ptr<InputStream> in, fs_->Open (file_name));
1605+ ASSERT_OK_AND_ASSIGN (int64_t length, in->Length ());
1606+ auto in_stream = std::make_shared<ArrowInputStreamAdapter>(in, arrow_pool_, length);
1607+
1608+ ASSERT_OK_AND_ASSIGN (
1609+ auto batch_reader,
1610+ ParquetFileBatchReader::Create (std::move (in_stream), options, 1024 , nullptr , arrow_pool_));
1611+
1612+ auto read_schema = arrow::schema ({arrow::field (" val" , arrow::int32 ())});
1613+ auto c_schema = std::make_unique<ArrowSchema>();
1614+ ASSERT_TRUE (arrow::ExportSchema (*read_schema, c_schema.get ()).ok ());
1615+
1616+ auto status = batch_reader->SetReadSchema (c_schema.get (), /* predicate=*/ nullptr , bitmap);
1617+ ASSERT_FALSE (status.ok ());
1618+ ASSERT_TRUE (status.IsInvalid ());
1619+ }
1620+
1621+ // / Test: "none" strategy performs no row-range refinement within a row group.
1622+ // /
1623+ // / 200 rows, 50 rows per page, 100 rows per row group → 2 row groups.
1624+ // / Bitmap: [0,10), [45, 50), [60, 70) — all within RG0 (rows 0-99).
1625+ // / Strategy: "none" → no refinement, so the entire RG0 (100 rows) is read.
1626+ // / Expected: 100 rows (0-99).
1627+ // / Compare with BitmapCoalesceTest (35 rows) and BitmapTrimStrategyTest (60 rows) which use
1628+ // / the same bitmap but apply refinement.
1629+ TEST_F (PageFilteredRowGroupReaderTest, BitmapNoneStrategyTest) {
1630+ std::string file_name = dir_->Str () + " /none_strategy.parquet" ;
1631+ auto data = MakeSequentialIntData (200 );
1632+ WriteTestFile (file_name, data, /* write_batch_size=*/ 50 , /* max_row_group_length=*/ 100 );
1633+
1634+ RoaringBitmap32 bitmap;
1635+ bitmap.AddRange (0 , 10 );
1636+ bitmap.AddRange (45 , 50 );
1637+ bitmap.AddRange (60 , 70 );
1638+
1639+ std::map<std::string, std::string> options;
1640+ options[PARQUET_READ_BITMAP_ROW_RANGE_REFINING_STRATEGY ] = " none" ;
1641+
1642+ auto read_schema = arrow::schema ({arrow::field (" val" , arrow::int32 ())});
1643+ std::shared_ptr<arrow::ChunkedArray> result;
1644+ ReadWithPredicateAndBitmapImpl (file_name, read_schema, /* predicate=*/ nullptr , bitmap, &result,
1645+ options);
1646+ ASSERT_TRUE (result);
1647+ ASSERT_EQ (100 , result->length ());
1648+
1649+ auto flat = arrow::Concatenate (result->chunks ()).ValueOrDie ();
1650+ auto struct_arr = std::dynamic_pointer_cast<arrow::StructArray>(flat);
1651+ ASSERT_TRUE (struct_arr);
1652+ auto val_arr = std::dynamic_pointer_cast<arrow::Int32Array>(struct_arr->field (0 ));
1653+ for (int32_t i = 0 ; i < 100 ; ++i) {
1654+ ASSERT_EQ (i, val_arr->Value (i));
1655+ }
1656+ }
1657+
1658+ // / Test: trim strategy with multiple columns — intersection of per-column trimmed ranges.
1659+ // /
1660+ // / 200 rows, 50 rows per page, 100 rows per row group → 2 row groups.
1661+ // / Two columns: a[i] = i, b[i] = i * 10.
1662+ // / Bitmap: [0,10), [45, 50), [60, 70) — same as BitmapTrimStrategyTest.
1663+ // / Both columns share the same page boundaries, so their trimmed ranges are identical.
1664+ // / The intersection is the same as either column alone:
1665+ // / - RG0 page 0 ([0,49]): trimmed to [0, 49] (50 rows)
1666+ // / - RG0 page 1 ([50,99]): trimmed to [60, 69] (10 rows)
1667+ // / Expected: 60 rows. Both columns must remain aligned after trimming.
1668+ TEST_F (PageFilteredRowGroupReaderTest, BitmapTrimMultiColumnTest) {
1669+ std::string file_name = dir_->Str () + " /trim_multi_col.parquet" ;
1670+ auto data = MakeTwoColumnData (200 );
1671+ WriteTestFile (file_name, data, /* write_batch_size=*/ 50 , /* max_row_group_length=*/ 100 );
1672+
1673+ RoaringBitmap32 bitmap;
1674+ bitmap.AddRange (0 , 10 );
1675+ bitmap.AddRange (45 , 50 );
1676+ bitmap.AddRange (60 , 70 );
1677+
1678+ std::map<std::string, std::string> options;
1679+ options[PARQUET_READ_BITMAP_ROW_RANGE_REFINING_STRATEGY ] = " trim" ;
1680+
1681+ auto read_schema =
1682+ arrow::schema ({arrow::field (" a" , arrow::int32 ()), arrow::field (" b" , arrow::int32 ())});
1683+ std::shared_ptr<arrow::ChunkedArray> result;
1684+ ReadWithPredicateAndBitmapImpl (file_name, read_schema, /* predicate=*/ nullptr , bitmap, &result,
1685+ options);
1686+ ASSERT_TRUE (result);
1687+ ASSERT_EQ (60 , result->length ());
1688+
1689+ auto flat = arrow::Concatenate (result->chunks ()).ValueOrDie ();
1690+ auto struct_arr = std::dynamic_pointer_cast<arrow::StructArray>(flat);
1691+ ASSERT_TRUE (struct_arr);
1692+ auto a_arr = std::dynamic_pointer_cast<arrow::Int32Array>(struct_arr->field (0 ));
1693+ auto b_arr = std::dynamic_pointer_cast<arrow::Int32Array>(struct_arr->field (1 ));
1694+ ASSERT_TRUE (a_arr);
1695+ ASSERT_TRUE (b_arr);
1696+ // RG0 page 0 trimmed to [0, 49]
1697+ for (int32_t i = 0 ; i < 50 ; ++i) {
1698+ ASSERT_EQ (i, a_arr->Value (i));
1699+ ASSERT_EQ (i * 10 , b_arr->Value (i));
1700+ }
1701+ // RG0 page 1 trimmed to [60, 69]
1702+ for (int32_t i = 0 ; i < 10 ; ++i) {
1703+ ASSERT_EQ (60 + i, a_arr->Value (50 + i));
1704+ ASSERT_EQ ((60 + i) * 10 , b_arr->Value (50 + i));
1705+ }
1706+ }
1707+
16181708} // namespace paimon::parquet::test
0 commit comments