Fix collecting SQL from schema editors while in transactions.
Review Request #12450 — Created July 10, 2022 and submitted
On Django 1.7 and higher, we utilize a database backend's
DatabaseSchemaEditorto generate a lot of our SQL. This is done by
putting the editor in SQL-collection mode, which tells it to record the
SQL statements it would use execute rather than executing them.
There's a design issue in SQLite's schema editor in Django 2.0 and
higher. Despite being put in SQL-collection mode, it will try to disable
foreign key checks and then check if it succeeded. If it did not (if,
say, in a transaction), it will immediately fail. This makes sense when
executing SQL, but not when collecting.
No other database backends have a check like this, so the failure case
was limited to SQLite.
There's no way to get around this through the standard usage of the
schema editor as a context manager, so instead we have to wrap it, put
it in the correct state, and collect the results ourselves.
This enables us to get the data we need without these side effects.
All call sites, including those that didn't explicitly put it into
SQL-collection mode (they weren't triggering calls that would have
executed SQL), now use the new wrapper function.
Unit tests pass for all versions of Django.