Skip to content

fix: deterministically name unnamed PK/FK so incremental constraints don't churn or collide#1561

Open
sd-db wants to merge 3 commits into
mainfrom
fix/unified-constraint-naming
Open

fix: deterministically name unnamed PK/FK so incremental constraints don't churn or collide#1561
sd-db wants to merge 3 commits into
mainfrom
fix/unified-constraint-naming

Conversation

@sd-db

@sd-db sd-db commented Jun 26, 2026

Copy link
Copy Markdown
Collaborator

What

Unnamed primary/foreign keys churned on every incremental run, and two or more unnamed foreign keys to the same parent failed with DELTA_CONSTRAINT_ALREADY_EXISTS. Databricks auto-names an unnamed key, so the model's name=None never matched the catalog read; the diff issued DROP CONSTRAINT ... CASCADE + re-add each run (silently dropping dependent FKs), and the unnamed FK re-adds collided on the server-derived <table>_<parent>_fk name.

Fix

dbt now assigns an unnamed PK/FK the same deterministic name its create-time macro already writes (synthesize_constraint_name), generated identically on the create and incremental paths, so the model and catalog agree and the diff is a no-op. A foreign key's name folds in its referenced columns (its full identity), so distinct FKs never collide — and a config that currently fails at create (two unnamed FKs from one column to different parent columns) becomes possible.

  • No change to the diff key or get_diff — once names are deterministic, the existing (name, columns) comparison + repoint reconciliation just work.
  • Macro↔Python name parity is pinned by TestConstraintNameParity so the two implementations can't drift while both exist.

Behavior

Existing unnamed foreign keys are renamed once on the next incremental run (a no-op DROP/re-add, no cascade), then stable — consistent with #1551 folding expression into the PK name in this same release. An unnamed key's expression/target edit is now reconciled (its name encodes it), unlike a named key (#1552 — still needs --full-refresh); the #1552 changelog note is scoped to named keys accordingly.

Tests

Supersedes #1554 (its unnamed-PK fix is reimplemented here more generally; its RELY-PK regression test is carried forward as an unnamed-PK variant).

Closes #1333
Closes #1344

…don't churn or collide

Databricks auto-names an unnamed primary/foreign key, so the model's name=None
never matched the catalog read and the incremental diff dropped and re-added it
every run (silently dropping dependent FKs); multiple unnamed FKs to one parent
collided on the server-derived <table>_<parent>_fk name.

dbt now assigns an unnamed PK/FK the same deterministic name its create-time
macro writes (synthesize_constraint_name), generated identically on the create
and incremental paths, so the model and catalog agree and the diff is a no-op.
A foreign key's name folds in its referenced columns, so distinct FKs never
collide. Macro/Python name parity is pinned by unit tests.

Closes #1333
Closes #1344
Supersedes #1554
@sd-db sd-db requested a review from jprakash-db as a code owner June 26, 2026 15:26
@github-actions

Copy link
Copy Markdown

Coverage report

Click to see where and how coverage changed

FileStatementsMissingCoverageCoverage
(new stmts)
Lines missing
  dbt/adapters/databricks
  constraints.py 187
  dbt/adapters/databricks/relation_configs
  constraints.py
Project Total  

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

@sd-db

sd-db commented Jun 26, 2026

Copy link
Copy Markdown
Collaborator Author

/integration-test

@github-actions

Copy link
Copy Markdown

Integration tests dispatched for PR #1561 by @sd-db. Track progress in the Actions tab.

@github-actions

Copy link
Copy Markdown

Integration results for PR #1561 — UC cluster ✅ success · SQL warehouse ❌ failure · All-purpose cluster ✅ success · Shard coverage ✅ success

Run details.

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

Labels

None yet

Projects

None yet

2 participants