Skip to content

Fixes #34933: Match FK referred columns to the parent table's column case - #34934

Merged
harshsoni2024 merged 1 commit into
mainfrom
fix/mysql-fk-referred-column-case
Oct 12, 2026
Merged

harshsoni2024 merged 1 commit into
mainfrom
fix/mysql-fk-referred-column-case

Conversation

@harshsoni2024

Copy link
Copy Markdown
Contributor

Describe your changes:

Fixes #34933

Ingestion rejected a whole MySQL table with Invalid column name id (400) when one of its foreign keys referenced the parent column in a different case: REFERENCES parent (id) while the column is Id. When the FK was deferred (e.g. on a first run), it was silently dropped instead. Full analysis and reproduction are in #34933.

Root cause

  • MySQL can store a foreign key's referenced column as typed. This happens when the FK was created with foreign_key_checks=0 before the parent table existed, or on MySQL 8.0.1–8.0.13. SQLAlchemy returns the name unchanged on 8.0.14+.
  • _prepare_foreign_constraints already loads the parent table from OpenMetadata, but it built referredColumns from that raw name. The server checks referred columns case-sensitively, so it rejected the table, or rejected the end-of-run FK PATCH when the FK had been deferred.
  • relationshipType was also wrong: MANY_TO_MANY instead of MANY_TO_ONE, because the parent's primary key wasn't found under the other casing.

Changes

  • metadata/utils/constraints.py: new resolve_column_names maps column names from the source to the stored ones. An exact match wins, then a single case-insensitive match. It returns None if a name matches no column or several.
  • _prepare_foreign_constraints builds referredColumns and the relationship type from the resolved names.
  • An FK whose referred column can't be resolved is retried after all tables are ingested, because the parent may gain the column later in the run. If it still can't be resolved, it's skipped with a warning instead of failing the table.

The fix is in ingestion rather than the server because the server's case-sensitive check is correct for case-sensitive sources, where a table can have both id and ID. Ingestion already normalizes a table's own constraint columns the same way in normalize_table_constraints.

Needs a backport to 2.0.x (reported on 2.0.3). On upstream/2.0 this function differs only in lines next to the change.

Type of change:

  • Bug fix

High-level design:

N/A: small bug fix (2 source files plus tests).

Tests:

Use cases covered

  • MySQL FK whose referenced column differs in case from the parent column: the table is ingested, and the FK points at the parent's stored column name with MANY_TO_ONE.
  • The same FK on both paths: deferred (parent not yet in OpenMetadata) and inline (parent already ingested).
  • Composite FK where only some referred columns differ in case.
  • When both id and ID exist, the exact match wins.
  • Referred column missing or matching several columns: the FK is retried, then skipped with a warning, and the table is still ingested.

Unit tests

  • I added unit tests for the new/changed logic.
  • Files: ingestion/tests/unit/topology/database/test_common_db_source.py, class TestPrepareForeignConstraintsReferredColumnCase (8 cases). 7 fail on main; the exact-match case passes on both, by design.
  • Coverage: every changed logic line is covered (21 of 23 changed lines; the other 2 are the import and def lines, which run before coverage starts).
  • tests/unit/topology/database and tests/unit/utils: the only difference in results between main and this branch is the new tests.

Backend integration tests

  • Not applicable (no backend changes).

Ingestion integration tests

  • I added/updated ingestion integration tests for connector changes.
  • I ran the integration tests covering my changed files locally.
  • File: ingestion/tests/integration/mysql/test_foreign_key_case.py. It creates an FK in the MySQL testcontainer that MySQL stores as REFERENCES fk_case_parent (id) against parent column Id (checked via SHOW CREATE TABLE), runs the metadata workflow twice, and checks the stored FK. It fails on main with Invalid column name id and passes on this branch.

Playwright (UI) tests

  • Not applicable (no UI changes).

Manual testing performed

  1. On mysql:8.0 (8.0.46), recreated the reported table, creating the child before the parent with SET foreign_key_checks = 0. SHOW CREATE TABLE shows REFERENCES <parent> (id) while the parent column is Id. MySQL enforces the FK (ERROR 1452 on a missing parent row).
  2. On main, ran metadata ingest twice against a local OpenMetadata server (2.0.0-SNAPSHOT):
    • Run 1, new service: the end-of-run FK PATCH failed with Invalid column name id, logged only as a warning. The workflow reported 100% success and the FK was missing.
    • Run 2: Failed to flush entities to bulk API … 'referredColumns': ['…<parent>.id'], 'relationshipType': 'MANY_TO_MANY' … message='Invalid column name id' status=400, and the workflow failed.
  3. On this branch, re-ran on the same service: the workflow succeeded and the table has the FK …<parent>.Id with MANY_TO_ONE.
  4. On another new service: run 1 added the FK through the end-of-run PATCH, and run 2 changed nothing.

UI screen recording / screenshots:

Not applicable.

Checklist:

  • I have read the CONTRIBUTING document.
  • My PR title is Fixes <issue-number>: <short explanation>
  • My PR is linked to a GitHub issue via Fixes #<issue-number> above.
  • I have commented on my code, particularly in hard-to-understand areas.
  • For JSON Schema changes: I updated the migration scripts or explained why it is not needed. (Not applicable)
  • For UI changes: I attached a screen recording and/or screenshots above. (Not applicable)
  • I have added tests (unit / integration / Playwright as applicable) and listed them above.
  • I have added a test that covers the exact scenario we are fixing.

…n case

MySQL can keep a foreign key's referenced column as written in the FK
definition (`REFERENCES limitadjustmentreasons (id)`) while the parent
column is `Id`. Ingestion built referredColumns from that raw name and the
server validates referred columns case-sensitively, so it rejected the whole
child table with `Invalid column name id`, or silently dropped the FK when
it was deferred to the end of the run.

Resolve each referred column against the parent table already fetched from
OpenMetadata: exact match first, then a single case-insensitive match. Use
the resolved names for the relationship type too, which reported
MANY_TO_MANY instead of MANY_TO_ONE. A referred column that still doesn't
resolve is retried after all tables are ingested, then skipped with a
warning instead of failing the table.
Copilot AI balanced review requested due to automatic review settings October 8, 2026 11:35
@harshsoni2024
harshsoni2024 requested a review from a team as a code owner October 8, 2026 11:35
@harshsoni2024
harshsoni2024 requested a review from IceS2 October 8, 2026 11:35

Copilot AI left a comment

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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@github-actions

github-actions Bot commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

❌ PR checklist incomplete

This PR cannot be merged until the following are addressed on its linked issue:

The fields live on the linked issue in the Shipping project (open the issue → right sidebar → Projects). After you set them, re-run this check (or push a commit) — issue/project changes do not re-trigger it automatically.

Maintainers can bypass this check by adding the skip-pr-checks label.

@github-actions github-actions Bot added Ingestion safe to test Add this label to run secure Github workflows on PRs labels Oct 8, 2026
@gitar-bot

gitar-bot Bot commented Oct 8, 2026

Copy link
Copy Markdown
Code Review ✅ Approved

🟡 Medium risk · Resolving and deferring foreign-key references changes ingestion metadata; unresolved references may be skipped, leaving relationship metadata incomplete.

Fixes MySQL foreign key ingestion when the referred column name differs in case from the parent table's stored column. The fix resolves column names case-insensitively during constraint preparation, retries unresolved FKs after all tables are ingested, and corrects the relationship type from MANY_TO_MANY to MANY_TO_ONE. Comprehensive unit and integration tests cover all scenarios including composite keys and ambiguous matches. No issues found.

Review coverage

📋 Rules No rules evaluated

🧪 Functional validation Not enabled · Set up

🤖 Auto-approval Not enabled · Set up

Options

Display: compact → Counting what did not apply, without listing it.

Comment with these commands to change the behavior for this request:

Compact
gitar display:verbose         

Was this helpful? React with 👍 / 👎 | Powered by Gitar — free for open source

@sonarqubecloud

sonarqubecloud Bot commented Oct 8, 2026

Copy link
Copy Markdown

@harshsoni2024
harshsoni2024 added this pull request to the merge queue Oct 12, 2026
Merged via the queue into main with commit 8aa6ad7 Oct 12, 2026
78 of 79 checks passed
@harshsoni2024
harshsoni2024 deleted the fix/mysql-fk-referred-column-case branch October 12, 2026 08:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Ingestion safe to test Add this label to run secure Github workflows on PRs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

MySQL: table rejected with "Invalid column name" when a foreign key references the parent column in a different case

3 participants