Commit Graph
23 Commits
Author SHA1 Message Date
David Cain 86b660fbf6 Also flag concurrent index creation
Creating indices concurrently (provided that index creation *completes*)
is generally a much safer way to build an index (since it allows reads
*and* writes to the table during index creation).

However, due to the inherent tradeoffs of concurrent index creation, the
operation will almost always take *longer* than a traditional (blocking)
index creation. It's actually much *more* important to lint against
concurrent index creation when an exclusive lock is open & held.

Test is from a comment by @David-Wobrock (I corrected syntax, though):
https://github.com/3YOURMIND/django-migration-linter/pull/251#discussion_r1249298197
2023-07-09 14:42:35 +02:00
David Cain 48fac8856b Downgrade CREATE_INDEX_EXCLUSIVE to a warning
While it's always a dangerous *pattern* to create an index while a
transaction is open & holds an exclusive lock, in practice it's not
always a big deal (for example, indexing a table with very few rows can
be fast). Accordingly, downgrade to a warning.
2023-07-09 14:42:35 +02:00
David Cain 0c5519d9dc Add new check for indexing with atomic=True
Briefly, this check helps prevent a long-running index creation from
preventing all reads and writes to a table.

This supplements an existing check
==================================
There is an existing check, `CREATE_INDEX` which warns about creating
indices without the `CONCURRENTLY` argument. It's a helpful check!

However, there are some valid reasons to prefer non-concurrent index
creation. For example, concurrent index creation may struggle to
complete when applied to write-heavy tables (since Postgres will have to
make repeated passes on the table to accommodate the new reads since the
last round).

The danger of `EXCLUSIVE` locks
===============================
If you *do* want to create indices nonconcurrently, there is still a
**huge footgun** to be aware of -- locks which are held in a transaction
are not released until the transaction closes.

Dangerous Django defaults
=========================
By default, any time you add a new Django field with `db_index=True` or
`unique=True`, the automatically generated `Migration` has:

- implicit setting of `atomic=True` (transactions are on)
- an `ALTER TABLE...ADD COLUMN` call (exclusively locks the table)
- a `CREATE INDEX` invocation (*hopefully* quick, due to nullable
  columns)

It's even more dangerous if you combine an `ALTER TABLE` call with
`CREATE INDEX` of an existing, non-nullable column.

Favor `atomic=False` if you must index
======================================
Index-creating migrations should have few `operations`. Since index
creation does not modify row-level data (and only requires locking
against writes), there's no reason to use transactions.

It's prudent to bypass the default `atomic=True` for index creation.
2023-07-09 14:42:35 +02:00
David Cain 9fdfa06845 Fix error output when warnings are found
We should log the *warnings* found, not errors!
2023-07-09 14:42:35 +02:00
David Wobrock 97a1f5c6c9 Fix #250 -- Don't consider partial index creation as making a column not nullable. 2023-07-03 20:41:03 +02:00
David Wobrock 2ee7dac3b3 Add internal classes and add type hints + mypy. 2022-12-26 16:26:24 +01:00
David Wobrock e8f83708b0 Run black. 2022-11-03 22:00:00 +01:00
Sondre Lillebø Gundersen bd4eb89b8c chore: Upgrade Python syntax with pyupgrade
Run with the following pre-commit configuration:

```
repos:
  - repo: https://github.com/asottile/pyupgrade
    rev: v3.1.0
    hooks:
      - id: pyupgrade
        args: [ "--py3-plus", "--py36-plus", "--py37-plus" ]
```

The rationale for every change can be found at https://github.com/asottile/pyupgrade
2022-11-03 22:00:00 +01:00
Sören Wegener a3fc5f1a50 Improve error message when an unsupported database vendor/SQL analyser was selected. 2022-10-03 15:48:11 +02:00
David Wobrock 76a55dbb12 Raise when unsupported db vendor, and add option to specify SQL analyser 2022-01-30 15:20:18 +01:00
David Wobrock 3219f9cf8a Handle creating a unique index as adding a unique constraint 2022-01-28 21:23:44 +01:00
David Wobrock 7674a51bc9 Fix #178 -- Don't detect an index creation when the table is being created 2021-12-20 22:38:54 +01:00
Christian Bundy 397c1f0e16 Default ends_with_default to False
Problem: Previously in gh-117 we aimed to solve gh-115, which described a problem where we used `SET DEFAULT` and then `DROP DEFAULT` immediately afterward. The solution was to track whether any defaults are retained, but the `ends_with_default` variable is initialized as `None` rather than `False`. At the end of the function we check whether `ends_with_default is False`, never occurs unless a default is set.

Solution: Assume that there is no default unless proven otherwise, and iniitializie `ends_with_default` to `False` instead of `None`.

Fixes: gh-158
2021-08-14 15:22:24 +02:00
David Wobrock fa56196f04 Add PG reindex linting warning and improve some smaller stuff 2021-06-19 18:15:40 +02:00
David Wobrock 27e492996c Apply black 2021-06-19 18:15:40 +02:00
David Wobrock 2bf87c0659 Add Postgresql warning when using DROP INDEX without CONCURRENTLY keyword 2021-06-19 18:15:40 +02:00
David Wobrock 343d163c88 Add Postgresql warning when using CREATE INDEX without CONCURRENTLY keyword 2021-06-19 18:15:40 +02:00
David Wobrock f21ff2c278 Add (failing) tests cases for makeing a column not null with a Django default value 2020-06-20 18:08:16 +02:00
David Wobrock 813c5c8690 Remove apache license headers in each file. The one full copy of the license at the root of the repo shall define the license for all source files. 2020-01-11 22:08:33 +01:00
David Wobrock cbc5a623b0 Add unit tests on adding many to many field (by testing SQL directly) 2019-10-21 22:25:01 +02:00
David Wobrock 652031ce8d Add failing tests for unique_together condition 2019-07-30 10:47:20 +02:00
David Wobrock 19620d9996 Handle other strategy for sqlite in Django2.2 2019-07-29 21:05:12 +02:00
David Wobrock ef2052a7b0 Work on SQL Analyser module
* With database specific functions
* Functions that analyse the entire transaction
* Unit tests that only test this module
2019-07-29 21:05:12 +02:00