transform() now works for tables referenced by views

Bracket the ALTER TABLE ... RENAME TO statements emitted by
transform_sql() with PRAGMA legacy_alter_table=ON/OFF. Since SQLite
3.25 the rename would otherwise rewrite references in every view
definition, which failed with "no such table" when a view referenced
the just-dropped table, and with keep_table= silently repointed
dependent views at the frozen backup table.

View definitions are now left byte-for-byte unchanged by a transform.

Closes #831

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Simon Willison 2026-08-06 22:08:37 -07:00
commit 8f264e8d2a
5 changed files with 179 additions and 2 deletions

View file

@ -1986,6 +1986,17 @@ A bare column name drops any foreign key that column participates in, including
Renaming a column with ``rename=`` updates any foreign keys that use it, and dropping a column with ``drop=`` also drops any foreign keys it participates in - for a compound foreign key this removes the whole constraint.
.. _python_api_transform_views:
Tables referenced by views
--------------------------
Tables that are referenced by views can be safely transformed - the view definitions are left byte-for-byte unchanged, and views continue to read from the live table even when ``keep_table=`` is used to keep a copy of the original around.
A view that references a column which the transform renamed or dropped will remain defined but will raise a ``no such column`` error when it is next queried. This is inherent to SQLite views, whose SQL is stored as text - if you rename or drop columns that a view depends on you should update that view definition yourself.
To achieve this, the SQL produced by ``transform_sql()`` brackets its ``ALTER TABLE ... RENAME TO`` statements with ``PRAGMA legacy_alter_table=ON`` and ``PRAGMA legacy_alter_table=OFF`` - without this, SQLite would attempt to rewrite references to the renamed table in every view definition, which fails when a view references the table that was just dropped. One consequence is that ``PRAGMA legacy_alter_table`` is reset to ``OFF`` (the SQLite default) after a transform, even if it was previously set to ``ON`` for the connection.
.. _python_api_transform_sql:
Custom transformations with .transform_sql()