alembic icon indicating copy to clipboard operation
alembic copied to clipboard

take use_alter=True, other FK / foreign key / foreignkey constraint rules into account when autogenerating create_table / drop_table

Open sqlalchemy-bot opened this issue 10 years ago • 20 comments

Migrated issue, originally created by Adrian Vogelsgesang (@vogelsgesang)

If the schema contains circular dependencies, the order of the CREATE TABLE statements is incorrect.

This is because metadata.sorted_tables (used here) returns the tables ordered alphabetically if there are circular dependencies.

sqlalchemy-bot avatar Sep 16 '15 16:09 sqlalchemy-bot

Michael Bayer (@zzzeek) wrote:

well there is no "correct" order if the tables have a cycle. The constraints have to be added with ALTER after the fact.

sqlalchemy-bot avatar Sep 16 '15 17:09 sqlalchemy-bot

Michael Bayer (@zzzeek) wrote:

see also #146

sqlalchemy-bot avatar Sep 16 '15 17:09 sqlalchemy-bot

Michael Bayer (@zzzeek) wrote:

We should be able to leverage sort_tables_and_constraints in order to break out CreateTable ops vs. individual create constraint ops; however those constraints would need to be removed from the rendered version of CreateTable. This can be applied right now as an end-user autogen filter so we could even make a recipe to start with. It probably needs to be done in a post-filtering style on the inside as well and since it breaks up the create table into components likely needs to remain a pretty clear switchable/optional thing, though a clean autogen should have it on by default. But of course it'll be wrong on SQLite. might need to be a flag, perhaps we can warn if cycles are detected and the flag is off.

sqlalchemy-bot avatar Sep 16 '15 17:09 sqlalchemy-bot

Michael Bayer (@zzzeek) wrote:

Issue #387 was marked as a duplicate of this issue.

sqlalchemy-bot avatar Sep 12 '16 15:09 sqlalchemy-bot

tomkcook (@tomkcook) wrote:

Moving discussion here from #387. I've had a go at implementing a simple version of this, by just ignoring foreign keys while comparing tables (nobbling _render_foreign_keys) and then comparing all the foreign keys on all the tables at the end - it works, but it feels like there should be pitfalls I haven't seen. I'll get it up on a bitbucket fork for review tomorrow.

sqlalchemy-bot avatar Sep 12 '16 17:09 sqlalchemy-bot

tomkcook (@tomkcook) wrote:

See https://bitbucket.org/tomkcook/alembic. 16 tests fail at present; I'm not at all familiar with the tests, but as far as I can tell the failing cases all work as intended. I'm not familiar enough with the inner workings of alembic to fix the tests so they actually test creation of foreign keys; if you give me a pointer on how to do it, I'll go through and fix them.

sqlalchemy-bot avatar Sep 13 '16 10:09 sqlalchemy-bot

tomkcook (@tomkcook) wrote:

I've got a vague feeling that this will do odd things if you drop a table that has foreign key constraints - it might well attempt to drop the table and then drop the constraint, which won't work. I guess the right way of doing this would be to replace _compare_tables from compare.py with something like _compare_tables_and_constraints and pass it the result of sqlalchemy.schema.sort_tables_and_constraints around compare.py:76.

Any comments?

sqlalchemy-bot avatar Sep 13 '16 12:09 sqlalchemy-bot

Michael Bayer (@zzzeek) wrote:

the mutually-dependent constraints problem also has to be addressed on the drop side, yes.

per my comment at https://bitbucket.org/zzzeek/alembic/issues/326/take-use_alter-true-other-fk-foreign-key#comment-21818371, I had envisioned the problem here being approached using a post-filtering approach. A filter like this might go into compare.py -> _populate_migration_script. I would extract ForeignKeyConstraint objects that need to have use_alter going on, and then put them into their own create_foreign_key ops down below the createtable / addcolumn calls they are associated with.

this is not an easy change because it has to fit cleanly into the plugin-oriented autogenerate architecture, and I had planned to get into this architecture again at some point to figure out the best way sorting filters like these can be applied internally. I don't have a decision on the best place to do it and I'd have to spend a bunch of time getting into that.

If you want to just play around on the outside, work with the process_revision_directives hook: http://alembic.zzzcomputing.com/en/latest/api/autogenerate.html#customizing-revision-generation. A recipe here can even go into the "recipes" section in the interim and/or form the basis of the built-in behavior.

sqlalchemy-bot avatar Sep 13 '16 13:09 sqlalchemy-bot

Michael Bayer (@zzzeek) wrote:

Issue #450 was marked as a duplicate of this issue.

sqlalchemy-bot avatar Sep 10 '17 00:09 sqlalchemy-bot

Changes by Michael Bayer (@zzzeek):

  • removed labels: bug
  • added labels: feature

sqlalchemy-bot avatar Sep 16 '15 17:09 sqlalchemy-bot

Changes by Michael Bayer (@zzzeek):

  • changed title from "incorrect migration script generated if schema con" to "take use_alter=True other FK constraint rules into"

sqlalchemy-bot avatar Sep 16 '15 17:09 sqlalchemy-bot

Changes by Michael Bayer (@zzzeek):

  • added labels: autogenerate - rendering

sqlalchemy-bot avatar Sep 16 '15 17:09 sqlalchemy-bot

Changes by Michael Bayer (@zzzeek):

  • set milestone to "fasttrack"

sqlalchemy-bot avatar Sep 16 '15 17:09 sqlalchemy-bot

Changes by Michael Bayer (@zzzeek):

  • changed milestone from "fasttrack" to "tier 1"

sqlalchemy-bot avatar Oct 16 '15 16:10 sqlalchemy-bot

Changes by Michael Bayer (@zzzeek):

  • changed title from "take use_alter=True other FK constraint rules into" to "take use_alter=True other FK / foreign key / forei"

sqlalchemy-bot avatar Sep 12 '16 15:09 sqlalchemy-bot

@CaselIT this is kind of a pretty big hole in autogenerate

zzzeek avatar Jul 07 '22 15:07 zzzeek

the idea would be render it as:

op.create_table()
op.create_table()
op.add_fk(...)
...

CaselIT avatar Jul 07 '22 19:07 CaselIT

yeah. we know how to determine that using what is now called sort_tables_and_constraints so this would need to be run and rearrange the tables somewhere between the compare and render phases. like perhaps sort and rearrange when we have the migration structure built.

zzzeek avatar Jul 07 '22 19:07 zzzeek

Hello, this issue is relevant to our work organization. I will try to tackle this in an upcoming merge request using the sqlalchemy sort_tables_and_constraints

adamsaimi avatar Feb 16 '24 09:02 adamsaimi