hanke580 opened a new issue, #26490:
URL: https://github.com/apache/datafusion/issues/26490

   ### Describe the bug
   
   
   Parquet writers leave NaN out of floating-point min/max statistics (the spec 
requires it). So a column chunk holding
   one distinct finite value plus some NaNs has statistics `min == max == x` 
and `null_count == 0`, although its values are
   not constant. DataFusion treats such a column as constant and substitutes 
the statistic for the data. A plain
   `SELECT * FROM 'file.parquet'` then returns `x` for every NaN row. There is 
no error, and NaNs silently disappear.
   pyarrow, DuckDB and Polars read the same file correctly.
   
   This is not limited to pruning: `datafusion.execution.parquet.pruning = 
false` and `enable_page_index = false` do not
   change the result. `datafusion.execution.collect_statistics = false` does. A 
`COPY … TO` from such a file writes the
   wrong values into the new files.
   
   The shortcut is `constant_columns_from_stats` / `constant_value_from_stats` 
in
   `datafusion/datasource-parquet/src/opener/mod.rs` (lines 1968 and 1999, 
called at line 891): `min == max &&
   !min.is_null() && null_count == Exact(0)`. For Float16/32/64, Parquet 
min/max cannot prove the column is constant, because NaN is excluded from them.
   So floating-point columns should not be treated as constant from these 
statistics (unless a NaN count of 0 is known).
   
   Draft PR #24804 (for #15812, pruning with NaN) would disable floating-point 
min/max in a way that also covers this
   ("constant-column substitution"), but it is a draft and has no issue for 
this user-visible symptom. I'm filing it so
   the wrong-result case is tracked and tested.
   
   
   ### To Reproduce
   
   
   ```python
   import pyarrow as pa, pyarrow.parquet as pq
   pq.write_table(pa.table({'c0': pa.array([float('nan'), -8.6e-27])}), 
'nan.parquet')
   pq.write_table(pa.table({'c0': pa.array([1.5, float('nan')], 
pa.float32())}), 'nan_f32.parquet')
   pq.write_table(pa.table({'c0': pa.array([float('nan'), -8.6e-27])}), 
'nan_nostats.parquet', write_statistics=False)
   ```
   
   ```
   $ datafusion-cli -q -c "SELECT * FROM 'nan.parquet';" -c "SELECT count(*) 
FILTER (WHERE isnan(c0)) AS nans FROM 'nan.parquet';"
   +----------+
   | c0       |
   +----------+
   | -8.6e-27 |
   | -8.6e-27 |      <-- this row is NaN in the file
   +----------+
   +------+
   | nans |
   +------+
   | 0    |
   +------+
   
   $ datafusion-cli -q -c "SELECT * FROM 'nan_f32.parquet';"
   | 1.5 |
   | 1.5 |            <-- NaN in the file
   
   $ datafusion-cli -q -c "SELECT * FROM 'nan_nostats.parquet';"
   | NaN      |
   | -8.6e-27 |       <-- correct without statistics
   
   $ datafusion-cli -q -c "SET datafusion.execution.collect_statistics = 
false;" -c "SELECT * FROM 'nan.parquet';"
   | NaN      |
   | -8.6e-27 |       <-- correct
   ```
   
   The same happens for files written by DataFusion's own `COPY`. `[NaN, 2.0, 
3.0]` (min ≠ max) and `[NaN, NaN]` (no min/max
   written) are read correctly.
   
   Both column orders are affected. The pyarrow files above have 
`TYPE_DEFINED_ORDER` and no `nan_count`. DataFusion/arrow-rs
   60 writes `IEEE_754_TOTAL_ORDER` with `nan_count`, but still leaves NaN out 
of min/max: `COPY (VALUES ('NaN'::double), (5.0))`
   gives `min = max = 5.0, null_count = 0, nan_count = 1`, and that file is 
read back as `5.0, 5.0`. So DataFusion ignores a
   `nan_count` that the file does carry.
   
   
   ### Expected behavior
   
   
   `SELECT * FROM 'nan.parquet'` returns `NaN, -8.6e-27`, as pyarrow, DuckDB 
and Polars do. Float statistics with `min == max`
   should not be used to replace the column by a constant, because NaN values 
are not reflected in them.
   
   
   ### Additional context
   
   - DataFusion main 290ad15 (2026-10-18), `datafusion-cli 55.1.0` built from 
source; also 91cd7ffb (2026-10-15). pyarrow 26.0.0.
   - Shapes like "one default value plus missing values as NaN" are common in 
sensor and ML feature data.
   - Related: #15812 and draft PR #24804.
   
   
   ### Willingness to contribute
   
   None


-- 
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