Opened 8 years ago
Last modified 6 years ago
#29182 closed Bug
SQLite database migration breaks ForeignKey constraint, leaving <table_name>__old in db schema — at Version 3
| Reported by: | ezaquarii | Owned by: | nobody |
|---|---|---|---|
| Component: | Migrations | Version: | 2.0 |
| Severity: | Release blocker | Keywords: | sqlite migration |
| Cc: | Simon Charette, Florian Apolloner, Adam Goode, Muflone | Triage Stage: | Accepted |
| Has patch: | yes | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description (last modified by )
SQLite table alteration uses rename and copy method. When running a database migration from Django command (via call_command('migrate')), database is left with references to <table_name>old table that has been dropped after migration.
This happens only when running SQLite DB migrations from management command.
Running migrations via ./manage.py migrate does not cause any issues.
This is the demonstration:
https://github.com/ezaquarii/openvpn-at-home/tree/sqlite-migration-bug
Steps to reproduce the bug
- build the project with
make devel
- enter Python virtualenv by
source backend/env/bin/activateand enterbackendsubdirectory
- run
./manage.py bootstrapto initialize the database
- bootstrap command runs db migration by calling
call_command('migrate')inopenvpnathome/apps/management/management/commands/bootstrap.py:37:openvpn_servertable is createdopenvpn_clienttable is created; it uses foreign key toopenvpn_server- another
openvpn_servermigration is run, adding dummy field openvpn_servertable is renamed toopenvpn_server__oldopenvpn_clientforeign key is re-linked toopenvpn_server__old- new table
openvpn_serveris created and data fromopenvpn_server__oldis copied with applied alterations openvpn_server__oldis droppedopenvpn_clientstill referencesopenvpn_sever__old- ForeignKey constraint is not updated and DB is left in unusable state
- try creating
Clientobject in django shell - SQL cannot be executed due to missing table
Exact commands (available in provided bug_repro.sh script):
cd backend make devel source ./env/bin/activate ./manage.py bootstrap echo ' Now type that: ./manage.py shell In [1]: from openvpnathome.apps.openvpn.models import Server, Client In [2]: Client.objects.create() ... snip ... OperationalError: no such table: main.openvpn_server__old '
Exported database schema clearly references deleted openvpn_server__old table:
CREATE TABLE "openvpn_client" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "created" datetime NOT NULL, "name" varchar(64) NOT NULL, "cert_id" integer NOT NULL REFERENCES "x509_cert" ("id") DEFERRABLE INITIALLY DEFERRED, "owner_id" integer NOT NULL REFERENCES "accounts_user" ("id") DEFERRABLE INITIALLY DEFERRED, "server_id" integer NOT NULL REFERENCES "openvpn_server__old" ("id") DEFERRABLE INITIALLY DEFERRED);
Please refer to db_schema.sql file placed in the backend subdirectory.
Tested with Django versions: 2.0.1 and 2.0.2
Change History (5)
by , 8 years ago
| Attachment: | bug_repro.sh added |
|---|
by , 8 years ago
| Attachment: | db_schema.sql added |
|---|
Database schema after running migrations - see references to temporary openvpn_serverold table
comment:1 by , 8 years ago
| Description: | modified (diff) |
|---|
follow-up: 3 comment:2 by , 8 years ago
Could you provide a more minimal project that reproduces the issue? In particular, the steps to reproduce shouldn't require installing a bunch of NodeJS packages. Thanks!
comment:3 by , 8 years ago
| Description: | modified (diff) |
|---|
Please check this repository:
https://github.com/ezaquarii/django-sqlite-migration-bug
Please check out bootstrap.py
with transaction.atomic():
call_command('migrate')
I think this is the issue. It works ok without transaction.
Bug reproduction steps as shell script