[ddl] ADD FOREIGN KEY can publish historical orphan rows when the referenced key contains NULL
- Dominant language
- Go
- Stars
- 40.5k
- Forks
- 6.2k
- PR merge metrics
- PR metrics pending
Description
## Bug Report
### 1. Minimal reproduce step (Required)
**Environment**
TiDB nightly ed2376acc6 and current master 05b396fb66 source
**Steps**
Create a parent table with nullable UNIQUE business_key and rows (1,1),(2,NULL). Create a child table with parent_key values 1 and 2. ADD FOREIGN KEY(parent_key) REFERENCES parent(business_key), then compare the public constraint with a NOT EXISTS orphan query.
### 2. What did you expect to see? (Required)
ADD FOREIGN KEY must reject any existing non-NULL child key that has no matching referenced key.
### 3. What did you see instead? (Required)
The ALTER succeeds, the foreign key becomes public, and one historical orphan remains. Removing only the parent NULL makes the same ALTER fail with error 1452.
### 4. What is your TiDB version? (Required)
TiDB nightly ed2376acc6 and current master 05b396fb66 source
Likely root cause and fix direction
**Likely root cause**
checkForeignKeyConstrain builds child_tuple NOT IN (SELECT referenced_tuple). SQL three-valued logic makes an absent child key evaluate UNKNOWN when the referenced subquery contains NULL, so the validator returns no violating row.
**Fix direction**
Use a correlated NOT EXISTS anti-join with equality on every foreign-key column, preserving the existing child IS NOT NULL filter. Add nullable referenced-key single and composite controls.
Contributor guide
Research direction
Start at the checkForeignKeyConstrain validator and reproduce the issue with a nullable referenced UNIQUE key and both child and parent rows described in the report. Check the existing child IS NOT NULL handling and validation query, then add coverage for nullable referenced-key single-column and composite cases; done means ADD FOREIGN KEY rejects every existing non-NULL orphan even when the referenced data contains NULL.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go, sql
- Domain
- databases
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 56/100