Skip to content

Return schema-preserving empty table on empty read result#9

Merged
xando merged 2 commits into
xando:masterfrom
sebastian-flyr:fix/empty-result-preserve-schema
Jun 10, 2026
Merged

Return schema-preserving empty table on empty read result#9
xando merged 2 commits into
xando:masterfrom
sebastian-flyr:fix/empty-result-preserve-schema

Conversation

@sebastian-flyr

Copy link
Copy Markdown
Contributor

Summary

When row_restrictions (or the source table) matches no rows, BigQuery's Storage Read API returns zero streams but still provides the table schema. The current code did not handle this:

  • engine="python" crashed on assert self.streams, "No streams to read, Table might be empty".
  • Both engines passed an empty iterator to pa.concat_tables(...), raising the unhelpful ArrowInvalid: Must pass at least one table.

This PR makes an empty result set return a zero-row pa.Table that preserves the BigQuery schema, for both engines:

  • reader._enter_python no longer asserts on empty streams; it starts no workers and keeps self.schema from the read session.
  • _next_python stops immediately when there are no streams, and the worker-split loop is skipped to avoid a ZeroDivisionError in to_split.
  • read_table / read_query collect batches and fall back to reader.schema.empty_table() when nothing is returned.

This keeps downstream code working (columns are always present) instead of crashing or silently dropping the schema.

Test plan

  • tests/unit/test_read_empty.py added, covering:
    • python engine: empty reader iterates as empty and exposes schema
    • python engine: read_table returns a 0-row table with the correct schema
    • rust engine: read_table returns a 0-row table with the correct schema
  • ruff check passes
  • pytest tests/unit passes (34 passed)

When `row_restrictions` (or the table itself) matches no rows, BigQuery
returns zero streams but still provides the table schema. Previously this
crashed: the Python engine hit `assert self.streams`, and both engines fed
an empty iterator into `pa.concat_tables`, raising
`ArrowInvalid: Must pass at least one table`.

Now `read_table` and `read_query` fall back to `reader.schema.empty_table()`,
returning a zero-row table that preserves the BigQuery schema for both the
python and rust engines.
Replace the mock-based unit tests with integration tests that write a real
table and read it back with a `row_restrictions` matching no rows, asserting
a zero-row table with the preserved schema for both the python and rust
engines, on read_table and read_query.
@xando
xando merged commit a19623d into xando:master Jun 10, 2026
0 of 5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants