Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
05180f4
refactor(db): composite PK on M2M association tables (sc-105349)
May 4, 2026
7606b07
fix(migration): always run NULL-FK cleanup; correct RLS test parent name
May 4, 2026
6c337c0
docs(migration): address SQLAlchemy review follow-ups
May 4, 2026
60c0472
refactor(migration): build pre-flight SQL via SQLAlchemy core (review)
May 4, 2026
76ba664
fix(migration): drop FKs before recreate on MySQL (sc-105349)
May 4, 2026
c4cdbca
fix(migration): MySQL downgrade FK + AUTO_INCREMENT (sc-105349)
May 5, 2026
7493cc7
fix(migration): explicit NOT NULL on FK columns for SQLite (sc-105349)
May 5, 2026
e75bab4
fix(migration): rebase down_revision onto 33d7e0e21daa (sc-105349)
May 5, 2026
3eeb18f
docs(UPDATING): add Postgres-targeted maintenance-window queries (sc-…
May 7, 2026
2ced3ad
docs(UPDATING): add MySQL-targeted maintenance-window queries (sc-105…
May 7, 2026
3d83276
build(docker): add MySQL compose override for dialect-swap evaluation
May 7, 2026
c20ad43
fix(docker): MySQL examples DB + EXAMPLES_PORT override (sc-105349)
May 7, 2026
53c6d0b
build(scripts): add stress-test data generator for migration timing
May 7, 2026
3dcc874
feat(scripts): add --dirty-duplicates-pct to seed_junction_load.py
May 7, 2026
251838c
fix(migration): skip alter_column nullable=False on non-SQLite (sc-10…
May 20, 2026
675df2b
fix(migration): address aminghadersohi review feedback (sc-105349)
May 20, 2026
7542334
fix(migration): allowlist guard on _downgrade_mysql_table
Jun 2, 2026
08669bc
fix(versioning): re-point composite-PK migration at master's head
Jun 11, 2026
abf3053
fix(versioning): capture FK list before dropping in composite-PK upgrade
Jun 11, 2026
73fdcc1
fix(migration): resumable MySQL upgrade + stale revision references
Jun 11, 2026
dfe1630
test(migration): cover the composite-PK data-cleanup paths
Jun 11, 2026
f19024b
docs(migration): correct composite-PK operator sizing guidance
Jun 11, 2026
eba6d7d
fix(db): re-point composite-PK migration onto current master head
Jun 17, 2026
f6b9401
docs(updating): trim composite-PK entry to a concise heads-up
Jun 29, 2026
d9924a5
chore(migration): re-point composite-PK migration onto current master…
Jul 1, 2026
60cf963
chore: drop MySQL scale-eval scaffolding from the PR
Jul 1, 2026
f54f0f0
test(migrations): fix idempotency-diff TypeError and synthetic-schema…
Jul 1, 2026
74cdde0
fix(migration): guard MySQL FK-rebuild against interrupted-run FK loss
Jul 1, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions UPDATING.md
Original file line number Diff line number Diff line change
Expand Up @@ -555,6 +555,29 @@ See `superset/mcp_service/PRODUCTION.md` for deployment guides.
}
```

### Composite primary keys on many-to-many association tables

Eight M:N association tables move from a synthetic `id INTEGER PRIMARY KEY` to a composite `PRIMARY KEY (fk1, fk2)` on their two foreign-key columns. The surrogate `id` is dropped, and the redundant `UNIQUE (fk1, fk2)` on the two tables that carried one is removed (now subsumed by the PK).

| Table | Composite PK |
|---|---|
| `dashboard_roles` | `(dashboard_id, role_id)` |
| `dashboard_slices` | `(dashboard_id, slice_id)` |
| `dashboard_user` | `(user_id, dashboard_id)` |
| `report_schedule_user` | `(user_id, report_schedule_id)` |
| `rls_filter_roles` | `(role_id, rls_filter_id)` |
| `rls_filter_tables` | `(table_id, rls_filter_id)` |
| `slice_user` | `(user_id, slice_id)` |
| `sqlatable_user` | `(user_id, table_id)` |

**Before upgrading:**

- The migration **deletes** two classes of pre-existing rows the composite PK cannot accommodate: duplicate `(fk1, fk2)` pairs (it keeps the lowest `id` and removes the rest) and rows with `NULL` in either FK column. Both are meaningless for `secondary=` association tables, but export the affected rows first if you need an audit record.
- External tooling (BI tools, backup scripts) that references the surrogate `id` on these tables will break; no application code references it.
- Downgrade restores the `id` column (and the original `UNIQUE` on the two tables that had it) but leaves the FK columns `NOT NULL` (intentional — a `NULL` FK in a junction row is meaningless).

For large `dashboard_slices` / `report_schedule_user` tables, see the operator runbook in [#39859](https://github.com/apache/superset/pull/39859) — pre-flight inventory queries, per-dialect lock-window sizing, and the duplicate / NULL-FK roll-up — to plan the maintenance window.

## 6.0.0
- [33055](https://github.com/apache/superset/pull/33055): Upgrades Flask-AppBuilder to 5.0.0. The AUTH_OID authentication type has been deprecated and is no longer available as an option in Flask-AppBuilder. OpenID (OID) is considered a deprecated authentication protocol - if you are using AUTH_OID, you will need to migrate to an alternative authentication method such as OAuth, LDAP, or database authentication before upgrading.
- [34871](https://github.com/apache/superset/pull/34871): Fixed Jest test hanging issue from Ant Design v5 upgrade. MessageChannel is now mocked in test environment to prevent rc-overflow from causing Jest to hang. Test environment only - no production impact.
Expand Down
35 changes: 26 additions & 9 deletions superset/connectors/sqla/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -1285,9 +1285,18 @@ def data(self) -> dict[str, Any]:
sqlatable_user = DBTable(
"sqlatable_user",
metadata,
Column("id", Integer, primary_key=True),
Column("user_id", Integer, ForeignKey("ab_user.id", ondelete="CASCADE")),
Column("table_id", Integer, ForeignKey("tables.id", ondelete="CASCADE")),
Column(
"user_id",
Integer,
ForeignKey("ab_user.id", ondelete="CASCADE"),
primary_key=True,
),
Column(
"table_id",
Integer,
ForeignKey("tables.id", ondelete="CASCADE"),
primary_key=True,
),
)


Expand Down Expand Up @@ -2218,17 +2227,25 @@ def text(self, clause: str) -> TextClause:
RLSFilterRoles = DBTable(
"rls_filter_roles",
metadata,
Column("id", Integer, primary_key=True),
Column("role_id", Integer, ForeignKey("ab_role.id"), nullable=False),
Column("rls_filter_id", Integer, ForeignKey("row_level_security_filters.id")),
Column("role_id", Integer, ForeignKey("ab_role.id"), primary_key=True),
Column(
"rls_filter_id",
Integer,
ForeignKey("row_level_security_filters.id"),
primary_key=True,
),
)

RLSFilterTables = DBTable(
"rls_filter_tables",
metadata,
Column("id", Integer, primary_key=True),
Column("table_id", Integer, ForeignKey("tables.id")),
Column("rls_filter_id", Integer, ForeignKey("row_level_security_filters.id")),
Column("table_id", Integer, ForeignKey("tables.id"), primary_key=True),
Column(
"rls_filter_id",
Integer,
ForeignKey("row_level_security_filters.id"),
primary_key=True,
),
)


Expand Down
Loading
Loading