Skip to content

fix(table): earlier set_statistics is not lost when remove_statistics follows it - #4087

Open
nmshr wants to merge 2 commits into
apache:mainfrom
nmshr:mshr/fix-remove-statistics-accumulate
Open

nmshr wants to merge 2 commits into
apache:mainfrom
nmshr:mshr/fix-remove-statistics-accumulate

Conversation

@nmshr

@nmshr nmshr commented Oct 7, 2026

Copy link
Copy Markdown

Rationale for this change

The remove_statistics() method on the statistics update builder is dropping updates which are queued before it.
This PR supersedes #3557

table.update_statistics() \
    .set_statistics(statistics_file) \
    .remove_statistics(other_snapshot_id) \
    .commit()

When remove_statistics() is called, the update queued by set_statistics() gets dropped, so at commit, only the remove is preserved. The side effects of this could be that the query engines plan with stale statistics.

This happens as = is used in remove_statistics() method. = replaces the builder's list of pending updates instead of appending to it. set_statistics() is using +=.

The fix is to use += in remove_statistics() method, like in set_statistics().

Are these changes tested?

Yes, test_update_statistics_set_then_remove_keeps_both_updates (tests/table/test_init.py) has been added as a new unit test.
Consider a table that has snapshots s2 and s1, each with its statistics files.
The test sets a new statistics file for s2, then removes s1's statistics.
After the commit, s2 points to the new file and s1 has no statistics. Both changes are applied.
On the main branch, this test fails, the set_statistics() for s2 gets dropped, s2 keeps pointing to its old file.
With the fix, make test, 4,254 passed, and make lint passing.

Are there any user-facing changes?

No API changes. set-then-remove now applies both updates.

AI disclosure

AI was used to write the code, tests and for local verification.

Anshul Mishra added 2 commits October 7, 2026 19:32
UpdateStatistics.remove_statistics assigned self._updates instead of
appending to it, so any set_statistics call staged earlier in the same
chain was silently dropped. For example,
table.update_statistics().set_statistics(f).remove_statistics(id).commit()
only removed the statistics and never registered f. This is the usage
shown in the class docstring and in the API docs.

Append with += like set_statistics does, and add a regression test that
chains set_statistics and remove_statistics and checks that both updates
are staged and applied.

Follow-up to apache#3557.
…test

Make the precondition explicit: the fixture already has statistics for
both snapshots, which is why remove_statistics targets the previous one.
Assert on the resulting table metadata only, instead of the private
staged updates.

This branch has not been deployed

No deployments
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.

1 participant