rich7420 opened a new issue, #4138:
URL: https://github.com/apache/iceberg-python/issues/4138

   ### Apache Iceberg version
   
   0.12.0 (latest release)
   
   ### Please describe the bug 🐞
   
   Also reproduces on main (d37149c).
   
   A scan pinned to an older snapshot reads the data with that snapshot's 
schema (`TableScan.projection()`), but the `row_filter` is bound to the table's 
current schema. If a column was dropped and a column with the same name added 
back, the name resolves to the new field id, which the old data files do not 
contain. The filter sees NULL in every row and the scan returns nothing, 
without an error.
   
   ```python
   import tempfile
   
   import pyarrow as pa
   import pyiceberg
   from pyiceberg.catalog.sql import SqlCatalog
   from pyiceberg.schema import Schema
   from pyiceberg.types import IntegerType, LongType, NestedField
   
   wh = tempfile.mkdtemp()
   cat = SqlCatalog("c", uri=f"sqlite:///{wh}/cat.db", warehouse=f"file://{wh}")
   cat.create_namespace("db")
   t = cat.create_table(
       "db.t",
       schema=Schema(
           NestedField(1, "id", LongType(), required=False),
           NestedField(2, "score", IntegerType(), required=False),
       ),
   )
   t.append(pa.table({"id": pa.array(range(100), pa.int64()), "score": 
pa.array(range(100), pa.int32())}))
   old = t.current_snapshot().snapshot_id
   
   # Drop `score`, then add a new column with the same name (it gets a new 
field id).
   with t.update_schema() as u:
       u.delete_column("score")
   with t.update_schema() as u:
       u.add_column("score", IntegerType())
   
   print(pyiceberg.__version__)
   old_rows = t.scan(snapshot_id=old).to_arrow()
   print(sum(s >= 50 for s in old_rows["score"].to_pylist()))  # 50: the old 
snapshot is read with its own schema
   print(t.scan(snapshot_id=old, row_filter="score >= 50").to_arrow().num_rows) 
 # expected 50
   print(t.scan(snapshot_id=old, row_filter="score >= 50").count())  # expected 
50
   ```
   
   ```
   0.12.0
   50
   0
   0
   ```
   
   On the same table and snapshot, Spark 3.5.6 with Iceberg 1.12.0 
(`spark.read.format("iceberg").option("snapshot-id", 
old).load(<metadata.json>).where("score >= 50").count()`) and DuckDB 1.5.6 
(`iceberg_scan(..., snapshot_from_id=old)`) both return 50.
   
   The filter is bound to `table_metadata.schema()` in `ArrowScan.__init__` 
(`pyiceberg/io/pyarrow.py`). `ManifestGroupPlanner` 
(`pyiceberg/table/__init__.py`) also uses the current schema for the partition 
projection and the manifest, partition, metrics and residual evaluators. 
`DataScan.count()` goes through the same `ArrowScan`, and scans via `use_ref()` 
set `snapshot_id` and take the same path.
   
   I have a fix: bind the row filter to the schema the scan reads (the 
snapshot's schema when `snapshot_id` is set) in both `ArrowScan` and 
`ManifestGroupPlanner`. Tests cover `to_arrow()`, the batch reader, `count()`, 
and a current-snapshot control. I can open a PR.
   
   ### Willingness to contribute
   
   - [x] I can contribute a fix for this bug independently
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to