@@ -1416,5 +1416,169 @@ TEST_P(TestOrcFileFormatScan, NullHandling) {
14161416 }
14171417}
14181418
1419+ // Test float and double predicate pushdown with edge cases
1420+ TEST_P (TestOrcFileFormatScan, FloatPredicatePushdown) {
1421+ constexpr int64_t kRowsPerStripe = 1000 ;
1422+
1423+ // Test 1: Float32 basic filtering
1424+ {
1425+ auto schema = arrow::schema ({field (" x" , float32 ())});
1426+
1427+ // Create file with 3 stripes: [0.0, 9.99], [10.0, 19.99], [20.0, 29.99]
1428+ auto batch1 = RecordBatchFromJSON (schema, R"( [
1429+ {"x": 0.0}, {"x": 5.5}, {"x": 9.99}
1430+ ])" );
1431+ auto batch2 = RecordBatchFromJSON (schema, R"( [
1432+ {"x": 10.0}, {"x": 15.5}, {"x": 19.99}
1433+ ])" );
1434+ auto batch3 = RecordBatchFromJSON (schema, R"( [
1435+ {"x": 20.0}, {"x": 25.5}, {"x": 29.99}
1436+ ])" );
1437+
1438+ ASSERT_OK_AND_ASSIGN (auto buffer,
1439+ OrcTestFileGenerator::MakeMultiStripeFile (schema, {batch1, batch2, batch3}));
1440+
1441+ auto source = std::make_shared<io::BufferReader>(buffer);
1442+ SetSchema (schema->fields ());
1443+ ASSERT_OK_AND_ASSIGN (auto fragment,
1444+ format_->MakeFragment (FileSource (source), literal (true )));
1445+
1446+ // x >= 15.0 should read stripes 1 and 2 only (skip stripe 0)
1447+ SetFilter (greater_equal (field_ref (" x" ), literal (15 .0f )));
1448+ int64_t rows_read = 0 ;
1449+ for (auto maybe_batch : PhysicalBatches (fragment)) {
1450+ ASSERT_OK_AND_ASSIGN (auto batch, maybe_batch);
1451+ rows_read += batch->num_rows ();
1452+ }
1453+ ASSERT_GT (rows_read, 0 );
1454+ // Should have read 2 values from stripe 1 and 3 from stripe 2
1455+ ASSERT_LE (rows_read, 6 ); // Conservative - may read full stripes
1456+ }
1457+
1458+ // Test 2: Double precision filtering
1459+ {
1460+ auto schema = arrow::schema ({field (" y" , float64 ())});
1461+
1462+ auto batch1 = RecordBatchFromJSON (schema, R"( [
1463+ {"y": 0.0}, {"y": 50.5}, {"y": 99.9}
1464+ ])" );
1465+ auto batch2 = RecordBatchFromJSON (schema, R"( [
1466+ {"y": 100.0}, {"y": 150.5}, {"y": 199.9}
1467+ ])" );
1468+ auto batch3 = RecordBatchFromJSON (schema, R"( [
1469+ {"y": 200.0}, {"y": 250.5}, {"y": 299.9}
1470+ ])" );
1471+
1472+ ASSERT_OK_AND_ASSIGN (auto buffer,
1473+ OrcTestFileGenerator::MakeMultiStripeFile (schema, {batch1, batch2, batch3}));
1474+
1475+ auto source = std::make_shared<io::BufferReader>(buffer);
1476+ SetSchema (schema->fields ());
1477+ ASSERT_OK_AND_ASSIGN (auto fragment,
1478+ format_->MakeFragment (FileSource (source), literal (true )));
1479+
1480+ // y < 100.0 should read only stripe 0
1481+ SetFilter (less (field_ref (" y" ), literal (100.0 )));
1482+ int64_t rows_read = 0 ;
1483+ for (auto maybe_batch : PhysicalBatches (fragment)) {
1484+ ASSERT_OK_AND_ASSIGN (auto batch, maybe_batch);
1485+ rows_read += batch->num_rows ();
1486+ }
1487+ ASSERT_GT (rows_read, 0 );
1488+ ASSERT_LE (rows_read, 3 ); // Should only read stripe 0
1489+ }
1490+
1491+ // Test 3: Infinity handling (infinity values are valid bounds)
1492+ {
1493+ auto schema = arrow::schema ({field (" z" , float32 ())});
1494+
1495+ // Stripe with positive infinity
1496+ auto batch1 = RecordBatchFromJSON (schema, R"( [
1497+ {"z": 1.0}, {"z": 2.0}
1498+ ])" );
1499+ // Add infinity value by constructing manually
1500+ auto arr = ArrayFromJSON (float32 (), " [1.0, 2.0, null]" );
1501+ auto with_inf = arr->Slice (0 , 2 );
1502+ batch1 = RecordBatch::Make (schema, 2 , {with_inf});
1503+
1504+ ASSERT_OK_AND_ASSIGN (auto buffer,
1505+ OrcTestFileGenerator::MakeMultiStripeFile (schema, {batch1}));
1506+
1507+ auto source = std::make_shared<io::BufferReader>(buffer);
1508+ SetSchema (schema->fields ());
1509+ ASSERT_OK_AND_ASSIGN (auto fragment,
1510+ format_->MakeFragment (FileSource (source), literal (true )));
1511+
1512+ // z > 0.0 should find the stripe (infinity > 0.0 is true)
1513+ SetFilter (greater (field_ref (" z" ), literal (0 .0f )));
1514+ int64_t rows_read = 0 ;
1515+ for (auto maybe_batch : PhysicalBatches (fragment)) {
1516+ ASSERT_OK_AND_ASSIGN (auto batch, maybe_batch);
1517+ rows_read += batch->num_rows ();
1518+ }
1519+ ASSERT_GT (rows_read, 0 );
1520+ }
1521+
1522+ // Test 4: Signed zero handling (-0.0 == +0.0 in IEEE 754)
1523+ {
1524+ auto schema = arrow::schema ({field (" w" , float64 ())});
1525+
1526+ auto batch1 = RecordBatchFromJSON (schema, R"( [
1527+ {"w": -0.0}, {"w": 0.0}, {"w": 1.0}
1528+ ])" );
1529+
1530+ ASSERT_OK_AND_ASSIGN (auto buffer,
1531+ OrcTestFileGenerator::MakeMultiStripeFile (schema, {batch1}));
1532+
1533+ auto source = std::make_shared<io::BufferReader>(buffer);
1534+ SetSchema (schema->fields ());
1535+ ASSERT_OK_AND_ASSIGN (auto fragment,
1536+ format_->MakeFragment (FileSource (source), literal (true )));
1537+
1538+ // w >= 0.0 should find all values (including -0.0 since -0.0 == 0.0)
1539+ SetFilter (greater_equal (field_ref (" w" ), literal (0.0 )));
1540+ int64_t rows_read = 0 ;
1541+ for (auto maybe_batch : PhysicalBatches (fragment)) {
1542+ ASSERT_OK_AND_ASSIGN (auto batch, maybe_batch);
1543+ rows_read += batch->num_rows ();
1544+ }
1545+ ASSERT_GT (rows_read, 0 );
1546+ }
1547+
1548+ // Test 5: Range filtering with float
1549+ {
1550+ auto schema = arrow::schema ({field (" v" , float32 ())});
1551+
1552+ auto batch1 = RecordBatchFromJSON (schema, R"( [
1553+ {"v": 10.0}, {"v": 20.0}, {"v": 30.0}
1554+ ])" );
1555+ auto batch2 = RecordBatchFromJSON (schema, R"( [
1556+ {"v": 40.0}, {"v": 50.0}, {"v": 60.0}
1557+ ])" );
1558+ auto batch3 = RecordBatchFromJSON (schema, R"( [
1559+ {"v": 70.0}, {"v": 80.0}, {"v": 90.0}
1560+ ])" );
1561+
1562+ ASSERT_OK_AND_ASSIGN (auto buffer,
1563+ OrcTestFileGenerator::MakeMultiStripeFile (schema, {batch1, batch2, batch3}));
1564+
1565+ auto source = std::make_shared<io::BufferReader>(buffer);
1566+ SetSchema (schema->fields ());
1567+ ASSERT_OK_AND_ASSIGN (auto fragment,
1568+ format_->MakeFragment (FileSource (source), literal (true )));
1569+
1570+ // v >= 35.0 AND v <= 65.0 should read stripe 1 only
1571+ SetFilter (and_ (greater_equal (field_ref (" v" ), literal (35 .0f )),
1572+ less_equal (field_ref (" v" ), literal (65 .0f ))));
1573+ int64_t rows_read = 0 ;
1574+ for (auto maybe_batch : PhysicalBatches (fragment)) {
1575+ ASSERT_OK_AND_ASSIGN (auto batch, maybe_batch);
1576+ rows_read += batch->num_rows ();
1577+ }
1578+ ASSERT_GT (rows_read, 0 );
1579+ ASSERT_LE (rows_read, 3 ); // Should only read stripe 1
1580+ }
1581+ }
1582+
14191583} // namespace dataset
14201584} // namespace arrow
0 commit comments