Skip to content

Fix two reload/update correctness issues noted in #95 - #115

Merged
roed314 merged 3 commits into
roed314:masterfrom
roed-math:fix-update-stats-swap
Jul 22, 2026
Merged

Fix two reload/update correctness issues noted in #95#115
roed314 merged 3 commits into
roed314:masterfrom
roed-math:fix-update-stats-swap

Conversation

@roed-math

Copy link
Copy Markdown

#95's description flagged two pre-existing oddities and left them for separate work; both are still present on master and neither is touched by any open PR. Each is fixed here in its own commit, with a regression test that fails without the change.

1. Non-inplace update_from_file(restat=True) never publishes the refreshed stats

The non-inplace path rebuilds the search table and, when restat is set, recomputes the counts and statistics into their _tmp tables — but the final swap was self._swap_in_tmp([self.search_table]), covering only the search table. So the recomputed statistics stayed in <counts>_tmp/<stats>_tmp, the live counts/stats kept their stale values, and the _tmp stats tables were left orphaned (exactly the leftovers #95's own preflight would later trip over). reload already includes the counts/stats tables in its swap list; this makes update_from_file do the same when it refreshed them.

Regression test asserts the live counts reflect the new data after the update (column_counts reads the stored counts, not a live recompute) and that no _tmp stats tables remain; a second test covers the no-restat path.

2. Dead _depN guard in _check_restricted_suffix

The guard rejecting user-chosen index/constraint names ending in a reserved suffix tested _depN with r"_dep[\d]+_$" — a trailing underscore that no generated name has. _rename_if_exists appends _dep<N> (just like the _old<N> that its working sibling r"_old[\d]+$" matches), so the guard never fired and a name colliding with the deprecation-renaming scheme could slip through. Dropped the stray underscore.

The existing restricted-suffix test is parametrized over every reserved suffix, so _depN is now covered alongside _tmp/_pkey/_oldN.

Suite 599 passed / 27 skipped locally (PG18, psycopg 3.3.4); ruff clean. Based directly on master (post-#96), so it merges independently of the rest of the wave.

🤖 Generated with Claude Code

roed314 and others added 3 commits July 21, 2026 18:00
When update_from_file(inplace=False, restat=True) rebuilt the search table it
recomputed the counts and stats into their _tmp tables, but the final swap
covered only the search table -- so the recomputed statistics never reached
the live names.  The stale counts/stats stayed in place and the freshly built
_tmp stats tables were orphaned (exactly the kind of leftover the reload
preflight in roed314#95 later flags).

Include the counts/stats tables in the swap when they were refreshed, the way
reload already builds its swap list.  Regression test covers both that the
live counts reflect the new data afterward and that no _tmp stats tables are
left behind (plus the no-restat path, which builds no _tmp stats at all).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The check rejecting user-chosen index/constraint names that end in a reserved
suffix tested for _depN with the regex `_dep[\d]+_$`, whose trailing underscore
no generated name ever has -- `_rename_if_exists` appends `_dep<N>` (like the
`_old<N>` its sibling guard `_old[\d]+$` matches).  So the _depN guard never
fired, and a name colliding with the deprecation-renaming scheme slipped
through.  Drop the stray underscore.

The existing restricted-suffix test is parametrized over every reserved suffix
so the _depN case is now covered too.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The previous commit added the counts/stats tables to the non-inplace
update_from_file swap so the refreshed statistics reach the live names.
But the _tmp counts table is built by _clone, which uses a bare
CREATE TABLE ... LIKE and copies no indexes, so swapping it in replaced
the indexed live counts table with an unindexed one -- cached-count
lookups (column_counts and friends) would then fall back to sequential
scans after update_from_file(inplace=False, restat=True).

Rebuild the standard counts indexes on the _tmp table before the swap,
exactly as reload already does (if self.stats.counts in tables:
_create_counts_indexes(suffix=suffix)).

The regression establishes the counts indexes the way a prior reload
would, runs the non-inplace restat update, and asserts they are still
present on the live counts table afterward; it fails without the rebuild.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@roed314
roed314 merged commit 667f441 into roed314:master Jul 22, 2026
16 checks passed
roed-math pushed a commit to roed-math/psycodict that referenced this pull request Jul 22, 2026
Rebased onto main, which absorbed everything this PR used to anticipate;
the reconciliation:

- Version: 1.0.0 is now set in psycodict.__init__.__version__, the single
  source of truth roed314#121 established -- pyproject keeps main's dynamic
  version, SPDX license string and >=3.9 floor, and this PR's classifiers
  drop the License:: entry (setuptools >= 77 rejects it next to an SPDX
  string) and the 3.8 entry.

- README: the rewrite now carries the Versioning.md pointer (roed314#123) in its
  Documentation list, which switches to relative links -- on the Sphinx
  site (roed314#122) those resolve to the copied guide pages, and they still
  render on GitHub; CHANGELOG and LICENSE stay absolute since neither is
  on the site.  Supported Python is 3.9+; blob/master URLs become
  blob/main.

- CHANGELOG: entries for the late wave -- sum/random honoring saving
  (roed314#118) and the 3.9 floor (roed314#121) under breaking changes; the docs site
  (roed314#122), Versioning.md/CONTRIBUTING/SECURITY and __version__ (roed314#121)
  under added; reload metafile+resort (roed314#114), update_from_file stats
  publication (roed314#115), copy_dumps delimiter escaping (roed314#116) under fixed;
  config.ini untracking (roed314#120), this release workflow and CITATION.cff
  (roed314#124) under infrastructure.

- release.yml: the flow notes now say bump __init__.__version__ and merge
  to main.

- Fixes the docs build on main, broken by the roed314#119 x roed314#122 crossing (roed314#119
  merged after roed314#122's last CI run): the Configuration docstring's nested
  defaults list needed blank lines to be valid RST under autodoc, and the
  README's relative LICENSE link had no target on the site.

Suite 857 passed / 36 skipped; ruff clean; sphinx -W clean; python -m
build + twine check --strict pass with Version 1.0.0,
License-Expression GPL-2.0-or-later, Requires-Python >=3.9 and no
License classifier in the wheel metadata.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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