Repository navigation
Conversation
For a cached query whose results are too large to return inline, jobs.query returns jobComplete, a pageToken, and no rows. BigQuery no longer sends totalRows for these responses, so routing them through QueryJob.result() returned an _EmptyRowIterator and query_and_wait silently returned 0 rows. ARROW rows never come from jobs.getQueryResults, so wait on the job only while the query runs. The RowIterator follows pageToken to the job's ReadRows stream. Fixes #18935
Contributor
There was a problem hiding this comment.
Code Review
This pull request removes the reached_max_results helper function and updates the query handling logic for ARROW serialization. Specifically, it ensures that when ARROW serialization options are present, the client does not wait on jobs.getQueryResults since ARROW rows are fetched via the ReadRows stream. It also updates comments and tests to handle cases where BigQuery leaves out totalRows for cached results that are too large to return inline, and adds unit tests to verify these behaviors. There are no review comments to address, so I have no feedback to provide.
daniel-sanche
approved these changes
Nov 2, 2026
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Context & Problem
query_and_wait(..., query_results_format="ARROW")returns 0 rows, with no error, when a query hits the cache and its results are too large to return inline. This is the cause of the intermittenttest_query_and_wait_arrow_cached_results[too_large_for_inline]system test failure in #18935.For these cache hits, the
jobs.queryresponse hasjobComplete: trueand apageToken, but no rows. BigQuery used to sendtotalRows: "0"for these responses. It is rolling out a change that leavestotalRowsout instead, because it doesn't know the count for cache hits. The test passes against backends that still send"0"and fails against the ones that don't, so it looks flaky during the rollout.Because of the
pageToken,query_and_waitpassed the response toQueryJob.result(). That method reads a missingtotalRowsas a statement without results, such as DDL, and returns an_EmptyRowIterator. The Arrow reader, which would have followed thepageTokento the job's ReadRows stream, never ran.Live probe of the cached ARROW
jobs.queryresponse before this change (18 of 18 runs):jobCompletetruepageTokentotalRowsSummary of Changes
_job_helpers.query_and_wait: for ARROW, wait on the job only whilejobCompleteis false. ARROW rows never come fromjobs.getQueryResults. TheRowIteratorreads the rows after the first page from the job's default ReadRows stream, and it only needsjobCompleteandpageTokento decide whether to read it. The default (JSON) format behaves as before, because itsRowIteratorstill pages throughjobs.getQueryResultsvia the job._arrow_query: removereached_max_results, which nothing calls anymore, because complete ARROW results no longer wait whether or notmax_resultswas reached. Fix the comment that saidtotalRowsis 0 for these cache hits.test_query_and_wait_arrow_waits_without_fetching_rowskeeps only thejobComplete: falsecase. Its other two cases asserted that complete responses with apageTokenwait on the job, which is the routing this change removes.test_query_and_wait_arrow_complete_with_page_token_doesnt_wait, which asserts that they don't wait. It also adds the response that caused the bug: complete, with apageTokenand nototalRows.rows.total_rowsisNonefor these cache hits, because BigQuery doesn't send the count. Before this change, the same queries returned no rows at all.Verification
tests/unit: 2824 passed, 43 skipped.flake8andblack==23.7.0are clean on the changed files.tests/system/test_arrow.pyagainst live BigQuery: 48 passed, 6 skipped, 6 xfailed. The xfails are expected failures already in the file: TIMESTAMP(12) isn't enabled in the test project, andjobs.querycan't send unnamed STRUCT fields.test_query_and_wait_arrow_cached_results[too_large_for_inline]passes against a backend that leaves outtotalRows, the same one that failed it every time before this change.Fixes #18935