Skip to content

Fix BEGIN leaking into SQL panel when using DatabaseCache store - #2397

Open
marcosalvesdev wants to merge 2 commits into
django-commons:mainfrom
marcosalvesdev:fix/2338-begin-commit-leak-sql-panel
Open

Fix BEGIN leaking into SQL panel when using DatabaseCache store#2397
marcosalvesdev wants to merge 2 commits into
django-commons:mainfrom
marcosalvesdev:fix/2338-begin-commit-leak-sql-panel

Conversation

@marcosalvesdev

Copy link
Copy Markdown

Description

Fixes #2338

When using CacheStore with Django's DatabaseCache backend, the transaction.atomic() calls used internally by the toolbar to persist its own data were emitting BEGIN/COMMIT (or SAVEPOINT/RELEASE SAVEPOINT inside a
test transaction) into the SQL panel. These commands carry no table name, so the existing
SKIP_TOOLBAR_QUERIES filter — which works by matching known toolbar table names in the SQL string — could
never suppress them.

The fix introduces a ContextVar (sql_recording, default True) in tracking.py and a context manager
no_sql_recording() that sets it to False for the duration of the toolbar's own persistence operations. The
decision logic in NormalCursorMixin._record() now consults this flag: when sql_recording=False, only
queries that explicitly reference a known toolbar table (and where SKIP_TOOLBAR_QUERIES=False) are recorded — preserving the existing opt-in behavior while suppressing table-less control commands unconditionally.

no_sql_recording() is applied in two places:

  • _UntrackedCache.untracked() — covers all cache operations made by CacheStore
  • DatabaseStore.set() and DatabaseStore.save_panel() — covers the transaction.atomic() calls made directly
    by DatabaseStore

Checklist:

  • I have added the relevant tests for this change.
  • I have added an item to the Pending section of docs/changes.rst.

AI/LLM Usage

  • This PR includes code generated with the help of an AI/LLM

@marcosalvesdev

marcosalvesdev commented Jun 27, 2026

Copy link
Copy Markdown
Author

👋🏼 Hey you!

Guys, the tox tests for SQLite are failing. I investigated it and found that the behavior expected in tests/panels/test_sql.py, which assumed that boolean parameters for non-PostgreSQL databases would be introduced in Django 6.2, was already introduced in 6.1. So I opened issue #2398. I was thinking about fixing it in this PR, but I would like to hear your thoughts first to make sure my findings are correct and the fix suggested in the issue is the right one.

@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown

Coverage report

Click to see where and how coverage changed

FileStatementsMissingCoverageCoverage
(new stmts)
Lines missing
  debug_toolbar
  store.py
  debug_toolbar/panels/sql
  tracking.py 273-274
Project Total  

This report was generated by python-coverage-comment-action

@marcosalvesdev

Copy link
Copy Markdown
Author

👋🏼 Hey you!

Guys, the tox tests for SQLite are failing. I investigated it and found that the behavior expected in tests/panels/test_sql.py, which assumed that boolean parameters for non-PostgreSQL databases would be introduced in Django 6.2, was already introduced in 6.1. So I opened issue #2398. I was thinking about fixing it in this PR, but I would like to hear your thoughts first to make sure my findings are correct and the fix suggested in the issue is the right one.

Fixed by #2403. Thanks @matthiask 👍🏼

Comment on lines +235 to +237
should_record = not skip_toolbar_queries and any(
table in sql for table in DDT_MODELS
)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't believe we want to hide the table-less commands here.



@contextlib.contextmanager
def no_sql_recording():

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the name here may be better as suppress_sql_recording as it's a bit clearer on its purpose.

Comment thread debug_toolbar/store.py
def save_panel(cls, request_id: str, panel_id: str, data: Any = None):
"""Save the panel data for the given request_id"""
with transaction.atomic():
from debug_toolbar.panels.sql.tracking import no_sql_recording

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this creates a circular dependency. It may be a good idea to move to a different place.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure. I used this aproach to avoid the circular import of tracking module. Some suggestion from where I can move the function?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tim-schilling is it fine to move the sql_recording and the suppress_sql_recording (old no_sql_recording) to debug_toolbar.utils? Or may I create a new module for this? Because of the import in panels.sql.__init__.py any module inside of panels.sql will cause the circular import. So the best solution I tested was create a new module outside of panels.sql or use the debug_toolbar.utils. What do you think?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think creating a new module would be fine, though perhaps we should rename it slightly so it's not tailored to the sql panel.

@tim-schilling tim-schilling left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for working on this. I think if we adopt the ContextVar approach, we can remove the SQL inspection logic altogether and solely rely on the ContextVar. Did you consider removing that?

@marcosalvesdev

marcosalvesdev commented Jul 14, 2026

Copy link
Copy Markdown
Author

Thank you for working on this. I think if we adopt the ContextVar approach, we can remove the SQL inspection logic altogether and solely rely on the ContextVar. Did you consider removing that?

I did, but I'd like to get the reviews first and have a best pic of what to do next. I wasn't sure if could be other applications for the SQL inspection before I remove it. What do you think?

@tim-schilling

Copy link
Copy Markdown
Member

I did, but I'd like to get the reviews first and have a best pic of what to do next. I wasn't sure if could be other applications for the SQL inspection before I remove it. What do you think?

@marcosalvesdev that SQL inspection was included for this use-case. I think if we need it again in the future, we can re-add it.

@marcosalvesdev

Copy link
Copy Markdown
Author

I did, but I'd like to get the reviews first and have a best pic of what to do next. I wasn't sure if could be other applications for the SQL inspection before I remove it. What do you think?

@marcosalvesdev that SQL inspection was included for this use-case. I think if we need it again in the future, we can re-add it.

Got it, I'll remove it so.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Using CacheStore with DatabaseCache backend shows BEGIN sql queries

2 participants