question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

gracefully handle when a migrator needs to modify a column that a view depends on

See original GitHub issue

Alembic version: 1.7.7 Alembic_utils version: 0.7.7 db: postgres 12

Here’s a basic setup:

-- pretend I have SQLAlchemy classes set up to create these
CREATE TABLE A (
  id integer not null primary_key,
  some_field varchar(255)
);

CREATE VIEW A_VIEW(id, some_field) AS
  SELECT id, some_field FROM A;

Now, suppose you wish to change some_field to a text column. I change the class, run alembic revision -m 'update table' --autogenerate.

Expected behavior: the column should upgrade successfully. Actual behavior: Postgres throws an error: “cannot alter type of a column used by a view or rule”

So, in other words, alembic_utils will successfully recreate views if the view definition is changed, but it doesn’t catch when table columns associated with those views get modified.

I’ve devised a workaround, but it would be nice if it could be done automatically somehow.

Here is my (admittedly naive) workaround to solve this problem in the current code:

# - dependent_view_names is a list of view names that my migration conflicts with
# - lambda_func: a function that does the actual migration steps
def _wrap(dependent_view_names, lambda_func):
    # start by retrieving the views that currently exist at migration time
    existing_views = {v.signature: v for v in PGView.from_database(op.get_bind(), 'public')}
    for view in dependent_view_names:
        if view in existing_views:
            # drop the view and any dependent views
            op.drop_entity(existing_views[view], cascade=True)
    # do the thing
    lambda_func()
    # we replace all views, because the cascade delete may have deleted multiple views.
    for view in existing_views:
        op.replace_entity(existing_views[view])

def upgrade():
    _wrap(['A_VIEW'], op.alter_column('A', 'some_field', existing_type=sa.VARCHAR(length=255), type_=sa.Text(), existing_nullable=True))

def downgrade():
    _wrap(['A_VIEW'], op.alter_column('A', 'some_field', existing_type=sa.TEXT(), type_=sa.VARCHAR(length=255), existing_nullable=True))

Issue Analytics

  • State:open
  • Created a year ago
  • Comments:8 (8 by maintainers)

github_iconTop GitHub Comments

1reaction
nstrong-scwcommented, May 5, 2022

Thanks for this!

I looked over the code behind recreate_dropped and it looks good to me. It’s certainly a nicer way to handle the issue, although it’d still be cool if the need for it could be auto-detected at generate time.

The logging tends to be a little chatty (the “Resolving entities with dependencies” message gets repeated across each round), but that’s a very minor complaint.

0reactions
oliricecommented, May 6, 2022

unfortunately i can not reproduce that error with 3.10.3 and the lib versions from pip freeze

It looks like its failing to find this key https://github.com/olirice/alembic_utils/blob/master/alembic.ini#L59 in this function https://github.com/olirice/alembic_utils/blob/5f670039a9a10722c0e5522370d8591831855e54/src/alembic_utils/testbase.py#L36

if you track it down I’d be happy to fix. In the meantime, please feel free to open PRs and let CI run the test suite for you as needed (mark as draft)

thanks

Read more comments on GitHub >

github_iconTop Results From Across the Web

How To Alter a Column Used By A View or Rule - Kagunda JM
Attempting to change the definition of activity_name column using ALTER TABLE boq_items ALTER activity_name TYPE text, ALTER activity_name SET ...
Read more >
Database Migrations: Modifying Existing Databases
The primary challenge when migrating an existing database is how to handle changes to the databases tables. The migration script must alter ......
Read more >
Migrating Room databases | Android Developers
Gracefully handle missing migration paths​​ . build(); This method tells Room to destructively recreate the tables in your app's database when it needs...
Read more >
Does renaming a database table via a migration on Heroku ...
The RENAME forms change the name of a table (or an index, sequence, view, materialized view, or foreign table), the name of an...
Read more >
Database migration: Concepts and principles (Part 1)
You can specify one or more data migration processes and execute them sequentially or concurrently depending on the needs of the migration. For ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found