#23379 closed Bug (fixed)
sql_create generates incorrect SQL with synced database
| Reported by: | flakfizer | Owned by: | Simon Charette |
|---|---|---|---|
| Component: | Database layer (models, ORM) | Version: | 1.7-rc-3 |
| Severity: | Release blocker | Keywords: | |
| Cc: | Triage Stage: | Ready for checkin | |
| Has patch: | yes | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description (last modified by )
The change between 1.6.6 to 1.7c3 in sql_create's first parameter from "app" to "app_config" is causing a bug, namely because app.get_models() returned a list, whereas app_config.get_models() returns a generator. This causes the "known_models" set to be larger than it should be.
This bug will cause invalid sql - mysql, in my case - to be generated if tables already exist, as shown in the attached reproduction app.
1) python manage.py repro # generates correct sql
CREATE TABLE `repro_app_a` ( `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, `b_id` integer NOT NULL ) ; CREATE TABLE `repro_app_b` ( `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, `a_id` integer NOT NULL ) ; ALTER TABLE `repro_app_b` ADD CONSTRAINT `a_id_refs_id_4838e71a` FOREIGN KEY (`a_id`) REFERENCES `repro_app_a` (`id`); ALTER TABLE `repro_app_a` ADD CONSTRAINT `b_id_refs_id_b49a3179` FOREIGN KEY (`b_id`) REFERENCES `repro_app_b` (`id`);
2) python manage.py migrate
3) python manage.py repro # generates incorrect sql; the first constraint fails because table repro_app_b hasn't been created yet.
CREATE TABLE `repro_app_a` ( `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, `b_id` integer NOT NULL ) ; ALTER TABLE `repro_app_a` ADD CONSTRAINT `b_id_refs_id_b49a3179` FOREIGN KEY (`b_id`) REFERENCES `repro_app_b` (`id`); CREATE TABLE `repro_app_b` ( `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, `a_id` integer NOT NULL ) ; ALTER TABLE `repro_app_b` ADD CONSTRAINT `a_id_refs_id_4838e71a` FOREIGN KEY (`a_id`) REFERENCES `repro_app_a` (`id`);
Fortunately, the (or, "a") fix is an easy one-liner:
-
django/core/management/sql.py
a b def sql_create(app_config, style, connection): 36 36 # We trim models from the current app so that the sqlreset command does not 37 37 # generate invalid SQL (leaving models out of known_models is harmless, so 38 38 # we can be conservative). 39 app_models = app_config.get_models(include_auto_created=True)39 app_models = set(app_config.get_models(include_auto_created=True)) 40 40 final_output = [] 41 41 tables = connection.introspection.table_names() 42 42 known_models = set(model for model in connection.introspection.installed_models(tables) if model not in app_models)
Attachments (1)
Change History (7)
by , 11 years ago
comment:1 by , 11 years ago
| Description: | modified (diff) |
|---|
comment:2 by , 11 years ago
| Owner: | changed from to |
|---|---|
| Severity: | Normal → Release blocker |
| Status: | new → assigned |
| Triage Stage: | Unreviewed → Accepted |
comment:4 by , 11 years ago
| Triage Stage: | Accepted → Ready for checkin |
|---|
comment:5 by , 11 years ago
| Resolution: | → fixed |
|---|---|
| Status: | assigned → closed |
Reproduction project