Skip to content

fix(import): isolate per-tag import in a SAVEPOINT to avoid poisoned session (#42912) - #42920

Open
waterWang wants to merge 2 commits into
apache:masterfrom
waterWang:fix/import-tag-savepoint-42912
Open

fix(import): isolate per-tag import in a SAVEPOINT to avoid poisoned session (#42912)#42920
waterWang wants to merge 2 commits into
apache:masterfrom
waterWang:fix/import-tag-savepoint-42912

Conversation

@waterWang

Copy link
Copy Markdown

Description

Closes #42912.

import_tag catches SQLAlchemyError after a query-triggered autoflush
failure (e.g. a concurrent unique-constraint violation) and continues
using the same SQLAlchemy Session without rolling back or isolating the
failed operation. The Session enters a pending-rollback state, and the
next operation raises PendingRollbackError.

Fix

Wrap each per-tag operation in a db_session.begin_nested() SAVEPOINT.
When a conflict occurs:

  • The SAVEPOINT is rolled back — only the failed tag's partial work is
    discarded
  • The outer session remains usable for subsequent tags
  • Other tags in the same import continue to succeed

Test

Added test_import_tag_savepoint_keeps_session_usable which simulates a
unique-constraint violation on the first tag and verifies that:

  • The second tag is still imported successfully
  • The session is not left in a pending-rollback state

@dosubot dosubot Bot added the change:backend Requires changing the backend label Aug 8, 2026
@bito-code-review

bito-code-review Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Code Review Agent Run #916fd7

Actionable Suggestions - 0
Review Details
  • Files reviewed - 2 · Commit Range: e47e145..c13bed2
    • superset/commands/importers/v1/utils.py
    • tests/unit_tests/charts/commands/importers/v1/import_test.py
  • Files skipped - 0
  • Tools
    • MyPy (Static Code Analysis) - ✔︎ Successful
    • Astral Ruff (Static Code Analysis) - ✔︎ Successful
    • Whispers (Secret Scanner) - ✔︎ Successful
    • Detect-secrets (Secret Scanner) - ✔︎ Successful

Bito Usage Guide

Commands

Type the following command in the pull request comment and save the comment.

  • /review - Manually triggers a full AI review.

  • /pause - Pauses automatic reviews on this pull request.

  • /resume - Resumes automatic reviews.

  • /resolve - Marks all Bito-posted review comments as resolved.

  • /abort - Cancels all in-progress reviews.

Refer to the documentation for additional commands.

Configuration

This repository uses Superset You can customize the agent settings here or contact your Bito workspace admin at evan@preset.io.

Documentation & Help

AI Code Review powered by Bito Logo

db_session.add(new_tagged_object)

new_tag_ids.append(tag.id)
new_tag_ids.append(tag.id)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggestion: new_tag_ids is mutated before the nested transaction flushes and releases its SAVEPOINT. If the association insert or SAVEPOINT release raises a SQLAlchemyError, the database work is rolled back but this ID remains in the returned list, causing old-association cleanup to treat the failed tag as successfully imported. Append the ID only after the nested context exits successfully. [logic error]

Severity Level: Minor 🧹
- ⚠️ Returned tag IDs can include rolled-back associations.
- ⚠️ Import cleanup can retain stale tag relationships.
- ⚠️ Concurrent tagged-object conflicts can trigger this path.

Fix in Cursor Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** superset/commands/importers/v1/utils.py
**Line:** 349:349
**Comment:**
	*Logic Error: `new_tag_ids` is mutated before the nested transaction flushes and releases its SAVEPOINT. If the association insert or SAVEPOINT release raises a `SQLAlchemyError`, the database work is rolled back but this ID remains in the returned list, causing old-association cleanup to treat the failed tag as successfully imported. Append the ID only after the nested context exits successfully.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

Comment on lines +545 to +547
add_count += 1
if add_count == 1:
raise SQLAlchemyError("UNIQUE constraint failed: tagged_object")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggestion: This test raises SQLAlchemyError directly from the mocked Session.add method, before SQLAlchemy performs an INSERT, autoflush, SAVEPOINT creation, or SAVEPOINT release. Consequently it does not exercise the database failure mode the production change targets and would still pass if rollback behavior during an actual flush or context-manager exit were broken. Trigger the violation during flush or configure the test database with a real conflicting unique row instead of raising from add. [possible bug]

Severity Level: Minor 🧹
- ⚠️ Regression coverage misses actual database constraint handling.
- ⚠️ Broken flush-time rollback could pass this test.
- ⚠️ Import concurrency behavior remains insufficiently tested.

Fix in Cursor Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** tests/unit_tests/charts/commands/importers/v1/import_test.py
**Line:** 545:547
**Comment:**
	*Possible Bug: This test raises `SQLAlchemyError` directly from the mocked `Session.add` method, before SQLAlchemy performs an INSERT, autoflush, SAVEPOINT creation, or SAVEPOINT release. Consequently it does not exercise the database failure mode the production change targets and would still pass if rollback behavior during an actual flush or context-manager exit were broken. Trigger the violation during flush or configure the test database with a real conflicting unique row instead of raising from `add`.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

@codecov

codecov Bot commented Aug 8, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 0% with 13 lines in your changes missing coverage. Please review.
✅ Project coverage is 66.41%. Comparing base (a75665b) to head (c13bed2).

Files with missing lines Patch % Lines
superset/commands/importers/v1/utils.py 0.00% 13 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master   #42920      +/-   ##
==========================================
- Coverage   66.41%   66.41%   -0.01%     
==========================================
  Files        2858     2858              
  Lines      161342   161343       +1     
  Branches    37162    37162              
==========================================
  Hits       107161   107161              
- Misses      52154    52155       +1     
  Partials     2027     2027              
Flag Coverage Δ
hive 38.24% <0.00%> (-0.01%) ⬇️
mysql 57.78% <0.00%> (-0.01%) ⬇️
postgres 57.82% <0.00%> (-0.01%) ⬇️
presto 40.19% <0.00%> (-0.01%) ⬇️
python 59.22% <0.00%> (-0.01%) ⬇️
sqlite 57.45% <0.00%> (-0.01%) ⬇️
unit 100.00% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

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

Labels

change:backend Requires changing the backend size/L

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] import_tag reuses a poisoned SQLAlchemy Session after concurrent tag conflict

1 participant