From cda16c4e2f7521ab04ad762e20fc44de8c137497 Mon Sep 17 00:00:00 2001 From: Wes Kendall Date: Tue, 23 Sep 2025 20:52:38 -0500 Subject: [PATCH 1/2] Ignore context tracking in SQL statements that are irrelevant or cause errors, like VACUUM --- CHANGELOG.md | 5 ++++ pghistory/runtime.py | 41 ++++++++++++++++++++------------- pghistory/tests/test_runtime.py | 17 ++++++++++---- pyproject.toml | 2 +- 4 files changed, 44 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ac70eb7..f0e8851 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Changelog +## 3.8.3 (2025-09-23) + +#### Fixes + - Ignore context tracking on VACUUM and other SQL statements that are either irrelevant or cause issues by [@wesleykendall](https://github.com/wesleykendall) in [#230](https://github.com/AmbitionEng/django-pghistory/pull/230). + ## 3.8.2 (2025-09-12) #### Fixes diff --git a/pghistory/runtime.py b/pghistory/runtime.py index 853a980..4db610c 100644 --- a/pghistory/runtime.py +++ b/pghistory/runtime.py @@ -22,24 +22,34 @@ Context = collections.namedtuple("Context", ["id", "metadata"]) - - -def _is_concurrent_statement(sql: Union[str, bytes]): +IGNORED_SQL_PREFIXES = ( + "select", + "vacuum", + "analyze", + "checkpoint", + "discard", + "load", + "cluster", + "reindex", + "create", + "alter", + "drop", +) + + +def _is_ignored_statement(sql: Union[str, bytes]): """ - True if the sql statement is concurrent and cannot be ran in a transaction - """ - sql = sql.strip().lower() if sql else "" - sql = sql.decode() if isinstance(sql, bytes) else sql - return sql.startswith("create") and "concurrently" in sql - + True if the sql statement is ignored for context tracking. + This includes select statements and other statements like vacuum. -def _is_dml_statement(sql: Union[str, bytes]): - """ - True if the sql statement is a dml statement (insert, update, delete) + Note: SQL is very complex. We may still inject context variables into + SQL that has CTEs, for example. Generally this should handle most cases + where it's impossible to even put a variable in the SQL, such as statements + that cannot be ran in a transaction (vacuum, etc). """ sql = sql.strip().lower() if sql else "" sql = sql.decode() if isinstance(sql, bytes) else sql - return not sql.startswith("select") + return sql.startswith(IGNORED_SQL_PREFIXES) def _is_transaction_errored(cursor): @@ -72,10 +82,9 @@ def _can_inject_variable(cursor, sql): setting. Ignore these cases for now. """ return ( - not getattr(cursor, "name", None) - and not _is_concurrent_statement(sql) + not _is_ignored_statement(sql) + and not getattr(cursor, "name", None) and not _is_transaction_errored(cursor) - and _is_dml_statement(sql) ) diff --git a/pghistory/tests/test_runtime.py b/pghistory/tests/test_runtime.py index 0c6a0a6..0597edd 100644 --- a/pghistory/tests/test_runtime.py +++ b/pghistory/tests/test_runtime.py @@ -9,13 +9,22 @@ "statement, expected", [ ("create index concurrently", True), - ("create index", False), + ("create index", True), + ("select * from auth_user", True), + ("vacuum table", True), + ("analyze table", True), + ("checkpoint table", True), + ("discard all", True), + ("load extension", True), + ("cluster", True), + ("update auth_user set id= %s where id = %s", False), (b"create index concurrently", True), - (b"create index", False), + (b"select * from auth_user", True), + (b"update auth_user set id= %s where id = %s", False), ], ) -def test_is_concurrent_statement(statement, expected): - assert pghistory.runtime._is_concurrent_statement(statement) == expected +def test_is_ignored_statement(statement, expected): + assert pghistory.runtime._is_ignored_statement(statement) == expected @pytest.mark.skipif( diff --git a/pyproject.toml b/pyproject.toml index 4c63f07..e438e61 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -30,7 +30,7 @@ packages = [ exclude = [ "*/tests/" ] -version = "3.8.2" +version = "3.8.3" description = "History tracking for Django and Postgres" authors = ["Wes Kendall"] classifiers = [ From ec49aac7d74a0bee67c17d8f5447e18f51ffa0fc Mon Sep 17 00:00:00 2001 From: Wes Kendall Date: Tue, 23 Sep 2025 20:57:20 -0500 Subject: [PATCH 2/2] fix release note --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f0e8851..fa8fcf8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ ## 3.8.3 (2025-09-23) #### Fixes - - Ignore context tracking on VACUUM and other SQL statements that are either irrelevant or cause issues by [@wesleykendall](https://github.com/wesleykendall) in [#230](https://github.com/AmbitionEng/django-pghistory/pull/230). + - Ignore context tracking on VACUUM and other SQL statements that are either irrelevant or cause issues by [@wesleykendall](https://github.com/wesleykendall) in [#232](https://github.com/AmbitionEng/django-pghistory/pull/232). ## 3.8.2 (2025-09-12)