Allow SQLExecutor to execute within a parent transaction, safely.

Review Request #11267 — Created Nov. 6, 2020 and submitted

Django Evolution

SQLExecutor was built to always require running outside of a
transaction, so that it could manage transactions itself. This was done
because some databases don't really support rollbacks of schema changes
properly within a transaction, and some operations in databases require
running outside a transaction (namely, SQLite renaming of primary keys).

However, it's not feasible to always run a database evolution fully
outside of a transaction. It won't happen, for instance, in Review Board
when installing/upgrading an extension, and it normally won't be a

Rather than outright fail, we now log a warning ahead of time. We then
check any grouping of SQL statements that are to be executed, check if
any require running outside a transaction (currnetly just the SQLite
primary key case), and then log and raise an exception to prevent
executing those statements.

This should cause statements to fail before any damage would be done,
invalidating the entire batch of evolutions.

Unit tests pass.

Verified this fixed an issue with unit test runs in Djblets.

Allow SQLExecutor to execute within a parent transaction, but warn.
  1. Ship It!
Review request changed

Status: Closed (submitted)

Change Summary:

Pushed to master (aa9d70f)