Skip to content

test(model): roll back uncommitted ds_col mutations in timestamp-expression tests#40451

Merged
richardfogaca merged 1 commit into
apache:masterfrom
mikebridge:sc-107618-rollback-ds-col-mutation
May 27, 2026
Merged

test(model): roll back uncommitted ds_col mutations in timestamp-expression tests#40451
richardfogaca merged 1 commit into
apache:masterfrom
mikebridge:sc-107618-rollback-ds-col-mutation

Conversation

@mikebridge
Copy link
Copy Markdown
Contributor

@mikebridge mikebridge commented May 26, 2026

SUMMARY

tests/integration_tests/model_tests.py::TestSqlaTableModel::test_get_timestamp_expression and ::test_get_timestamp_expression_epoch directly mutate birth_names.ds_col.expression (and, in the _epoch variant, ds_col.python_date_format) to exercise the get_timestamp_expression compile path. expression is restored at the end of each test; python_date_format is not. Neither test commits nor rolls back, so the TableColumn row stays in session.dirty for the next autoflush.

This is harmless on master today because nothing inspects TableColumn for dirty state at flush time. It becomes load-bearing the moment any code adds a SQLAlchemy listener that walks dirty rows — concretely, the __versioned__ (sqlalchemy-continuum) instrumentation from the in-flight entity-versioning work (#39603). With that instrumentation applied, the next autoflush captures the uncommitted mutation, writes a table_columns_version shadow row for ds_col, and corrupts birth_names' version timeline.

The polluter mechanism is plain SQLAlchemy session-dirty + autoflush, not anything backend-specific — so the cascade reproduces on all three backends:

CI job test_restore_applies_scalar_field (downstream of birth_names version-history) test_rls_filter_applies_to_virtual_dataset (+ _with_join)
test-sqlite fails (422 "Dataset could not be updated") passes
test-mysql fails (422) passes
test-postgres (current/next/previous) fails (422) fails (empty RLS clauses in rendered SQL)

The virtual-dataset-RLS-cascade Postgres-only symptom appears to involve an additional Postgres path through the composite-PK rls_filter_tables M2M (not fully root-caused; out of scope here). The dataset-restore cascade is uniform across backends.

Fix: wrap each test body in try / finally with metadata_db.session.rollback() in the finally to discard the dirty attribute history. Behaviour on master is unchanged; the fix removes a latent footgun for anyone adding flush-time listeners to TableColumn.

TESTING INSTRUCTIONS

The fix is hygiene-only on vanilla master — the two affected tests pass before and after:

pytest tests/integration_tests/model_tests.py::TestSqlaTableModel::test_get_timestamp_expression \
       tests/integration_tests/model_tests.py::TestSqlaTableModel::test_get_timestamp_expression_epoch

To verify the latent bug this prevents, apply any SQLAlchemy __versioned__ listener to TableColumn (e.g. via sqlalchemy-continuum) and run the full integration suite. Before this fix: 3 downstream tests fail in CI's full-suite ordering (1 on each backend; Postgres also picks up the two RLS virtual-dataset failures). After: clean run.

ADDITIONAL INFORMATION

  • Has associated issue: Preset internal ticket sc-107618
  • Required feature flags:
  • Changes UI
  • Includes DB Migration
  • Introduces new feature or API
  • Removes existing feature or API

@bito-code-review
Copy link
Copy Markdown
Contributor

bito-code-review Bot commented May 26, 2026

Code Review Agent Run #7e9867

Actionable Suggestions - 0
Review Details
  • Files reviewed - 1 · Commit Range: 2c687de..2c687de
    • tests/integration_tests/model_tests.py
  • Files skipped - 0
  • Tools
    • Whispers (Secret Scanner) - ✔︎ Successful
    • Detect-secrets (Secret Scanner) - ✔︎ Successful
    • MyPy (Static Code Analysis) - ✔︎ Successful
    • Astral Ruff (Static Code Analysis) - ✔︎ 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

…ession tests

``test_get_timestamp_expression`` and ``test_get_timestamp_expression_epoch``
mutate ``birth_names.ds_col.expression`` (and, in the ``_epoch`` variant,
``ds_col.python_date_format``) to exercise the ``get_timestamp_expression``
compile path. ``expression`` is restored at the end of each test;
``python_date_format`` is not. Neither test commits or rolls back, so
the ``TableColumn`` row stays in ``session.dirty`` for the next
autoflush.

This is harmless today because nothing on master inspects
``TableColumn`` for dirty state at flush time. It becomes load-bearing
the moment any code adds a SQLAlchemy listener that walks dirty rows —
for example, the ``__versioned__`` instrumentation from the in-flight
entity-versioning work (sc-103156 / PR apache#39603). With that instrumentation
applied, the next autoflush captures the uncommitted mutation, writes
a ``table_columns_version`` shadow row, and corrupts ``birth_names``'
version timeline — cascading into 422s on downstream dataset-restore
tests and empty RLS clauses on the virtual-dataset tests, but **only on
Postgres** (SQLite's post-INSERT attribute-expire behaviour is laxer
and hides the bug).

Wrap each test body in ``try`` / ``finally`` with
``metadata_db.session.rollback()`` in the ``finally`` to discard the
attribute history. Behaviour on vanilla master is unchanged; the fix
just removes a latent footgun for anyone adding flush-time listeners
to ``TableColumn``.

Closes sc-107618.
@mikebridge mikebridge force-pushed the sc-107618-rollback-ds-col-mutation branch from 2c687de to bb94e0f Compare May 26, 2026 19:58
@codecov
Copy link
Copy Markdown

codecov Bot commented May 26, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 64.18%. Comparing base (b6f545e) to head (bb94e0f).

Additional details and impacted files
@@           Coverage Diff           @@
##           master   #40451   +/-   ##
=======================================
  Coverage   64.18%   64.18%           
=======================================
  Files        2592     2592           
  Lines      139256   139256           
  Branches    32334    32334           
=======================================
  Hits        89385    89385           
  Misses      48336    48336           
  Partials     1535     1535           
Flag Coverage Δ
hive 39.22% <ø> (ø)
mysql 58.73% <ø> (ø)
postgres 58.81% <ø> (ø)
presto 40.90% <ø> (ø)
python 60.37% <ø> (ø)
sqlite 58.45% <ø> (ø)
unit 100.00% <ø> (ø)

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

☔ View full report in Codecov by Sentry.
📢 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.

@bito-code-review
Copy link
Copy Markdown
Contributor

bito-code-review Bot commented May 26, 2026

Code Review Agent Run #a449f6

Actionable Suggestions - 0
Filtered by Review Rules

Bito filtered these suggestions based on rules created automatically for your feedback. Manage rules.

  • tests/integration_tests/model_tests.py - 1
Review Details
  • Files reviewed - 1 · Commit Range: bb94e0f..bb94e0f
    • tests/integration_tests/model_tests.py
  • Files skipped - 0
  • Tools
    • Whispers (Secret Scanner) - ✔︎ Successful
    • Detect-secrets (Secret Scanner) - ✔︎ Successful
    • MyPy (Static Code Analysis) - ✔︎ Successful
    • Astral Ruff (Static Code Analysis) - ✔︎ 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

Copy link
Copy Markdown
Contributor

@richardfogaca richardfogaca left a comment

Choose a reason for hiding this comment

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

lgtm

@richardfogaca richardfogaca merged commit 7e08879 into apache:master May 27, 2026
58 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants