awadhesh14 opened a new pull request, #19897:
URL: https://github.com/apache/hudi/pull/19897

   ### Describe the issue this Pull Request addresses
   
   Queries with empty projections against Lance-backed Hudi tables (such as 
`df.count()`, `COUNT(*)`, `COUNT(1)`, `SELECT 1`, and `EXISTS(...)`) previously 
returned 0 rows or failed.
   
   `SparkLanceReaderBase` previously had a short-circuit returning 
`Iterator.empty` when `requiredSchema.isEmpty && partitionSchema.isEmpty`. 
Furthermore, if `requiredSchema.isEmpty` or if an older file slice lacked all 
requested columns under schema evolution, `filterSchemaByFileSchema` produces 
an empty `iteratorSchema`, which caused schema-validation checks in 
`LanceRecordIterator` to fail or misalign.
   
   ### Summary and Changelog
   
   1. **Metadata-only empty projection iterator**:
      - Replaced premature `Iterator.empty` in `SparkLanceReaderBase.scala` 
with a branch on `iteratorSchema.isEmpty` to 
`LanceRecordIterator.emptyProjectionIterator(...)`.
      - Obtains the exact row count from Lance file metadata via 
`lanceReader.numRows()`, eliminating data-column I/O for count and 
empty-projection queries.
      - Yields valid, zero-field `UnsafeRow`s using a reusable, fully 
initialized singleton (`row.pointTo(new byte[0], 0)`).
   2. **Schema evolution and null padding**:
      - When an older file slice lacks newly added columns requested by Spark, 
`filterSchemaByFileSchema` produces an empty `iteratorSchema`. The reader emits 
$N$ metadata rows with zero data-column I/O, which are then correctly populated 
with `NULL`s via 
`SparkSchemaTransformUtils.generateNullPaddingProjection(iteratorSchema, 
requiredSchema)`.
   3. **Safety & Invariants**:
      - Guarded reader lifecycle in `SparkLanceReaderBase.scala` so that 
`lanceReader` is closed on exception paths if an exception occurs before the 
iterator is initialized.
      - Handled zero-field Spark schemas in 
`LanceRecordIterator.buildColumnVectors` returning `new ColumnVector[0]`.
      - Verified the MOR merge invariant: uncompacted log files on MOR trigger 
file-group reading which injects mandatory merge keys (`_hoodie_record_key`, 
precombine, delete markers), correctly routing through the merge path rather 
than this metadata-only shortcut.
   4. **Comprehensive Tests**:
      - Added unit tests in `TestLanceRecordIterator` covering 
`createEmptyUnsafeRow`, lifecycle, zero-row edge cases, and empty schema batch 
handling with clean Arrow buffer management.
      - Added unit test in `TestSparkSchemaTransformUtils` verifying null 
padding from an empty input schema.
      - Added integration regression tests in `TestLanceDataSource` covering 
unpartitioned count, partitioned count, zero-row counts after delete, and 
multi-commit schema evolution with missing columns across COW and MOR.
   
   ### Impact
   
   - Fixes correctness for `df.count()`, `COUNT(*)`, `SELECT 1`, and empty 
projections on Lance tables.
   - Drastically speeds up count queries on Lance tables by avoiding 
unnecessary data-column scans and deriving cardinality directly from file 
metadata (`numRows()`).
   - Correctly handles schema evolution queries requesting only newly added 
columns against older Lance files.
   
   ### Risk Level
   
   low
   
   ### Documentation Update
   
   none
   
   ### Contributor's checklist
   
   - [x] Read through [contributor's 
guide](https://hudi.apache.org/contribute/how-to-contribute)
   - [x] Enough context is provided in the sections above
   - [x] Adequate tests were added if applicable
   


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

Reply via email to