Skip to content

Commit d1dee70

Browse files
authored
Merge pull request #3102 from dolthub/elianddb/9494-fix-mixed-string-foreign-keys
dolthub/dolt#9494 - Clean up mixed string foreign key logic
2 parents 60e98ba + 04263a3 commit d1dee70

File tree

2 files changed

+32
-34
lines changed

2 files changed

+32
-34
lines changed

enginetest/queries/foreign_key_queries.go

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2807,21 +2807,18 @@ var CreateForeignKeyTests = []ScriptTest{
28072807
ExpectedErrStr: "string 'abc' is too large for column 'c'",
28082808
},
28092809
{
2810-
Skip: true,
28112810
Query: "create table child_varchar_10 (vc varchar(10), foreign key (vc) references parent(c));",
28122811
Expected: []sql.Row{
28132812
{types.NewOkResult(0)},
28142813
},
28152814
},
28162815
{
2817-
Skip: true,
28182816
Query: "insert into child_varchar_10 values ('abc');",
28192817
Expected: []sql.Row{
28202818
{types.NewOkResult(1)},
28212819
},
28222820
},
28232821
{
2824-
Skip: true,
28252822
Query: "insert into child_varchar_10 values ('abcdefghij');",
28262823
ExpectedErr: sql.ErrForeignKeyChildViolation,
28272824
},
@@ -2850,21 +2847,18 @@ var CreateForeignKeyTests = []ScriptTest{
28502847
ExpectedErrStr: "string 'abc' is too large for column 'b'",
28512848
},
28522849
{
2853-
Skip: true,
28542850
Query: "create table child_varbinary_10 (vb varbinary(10), foreign key (vb) references parent(b));",
28552851
Expected: []sql.Row{
28562852
{types.NewOkResult(0)},
28572853
},
28582854
},
28592855
{
2860-
Skip: true,
28612856
Query: "insert into child_varbinary_10 values ('abc');",
28622857
Expected: []sql.Row{
28632858
{types.NewOkResult(1)},
28642859
},
28652860
},
28662861
{
2867-
Skip: true,
28682862
Query: "insert into child_varbinary_10 values ('abcdefghij');",
28692863
ExpectedErr: sql.ErrForeignKeyChildViolation,
28702864
},

sql/plan/alter_foreign_key.go

Lines changed: 32 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -644,36 +644,40 @@ func FindFKIndexWithPrefix(ctx *sql.Context, tbl sql.IndexAddressableTable, pref
644644
// foreignKeyComparableTypes returns whether the two given types are able to be used as parent/child columns in a
645645
// foreign key.
646646
func foreignKeyComparableTypes(ctx *sql.Context, type1 sql.Type, type2 sql.Type) bool {
647-
if !type1.Equals(type2) {
648-
// There seems to be a special case where CHAR/VARCHAR/BINARY/VARBINARY can have unequal lengths.
649-
// Have not tested every type nor combination, but this seems specific to those 4 types.
650-
if type1.Type() == type2.Type() {
651-
switch type1.Type() {
652-
case sqltypes.Char, sqltypes.VarChar, sqltypes.Binary, sqltypes.VarBinary:
653-
type1String := type1.(sql.StringType)
654-
type2String := type2.(sql.StringType)
655-
if type1String.Collation().CharacterSet() != type2String.Collation().CharacterSet() {
656-
return false
657-
}
658-
case sqltypes.Enum:
659-
// Enum types can reference each other in foreign keys regardless of their string values.
660-
// MySQL allows enum foreign keys to match based on underlying numeric values.
661-
return true
662-
case sqltypes.Decimal:
663-
// MySQL allows decimal foreign keys with different precision/scale
664-
// The foreign key constraint validation will handle the actual value comparison
665-
return true
666-
case sqltypes.Set:
667-
// MySQL allows set foreign keys to match based on underlying numeric values.
668-
return true
669-
default:
670-
return false
671-
}
672-
} else {
673-
return false
647+
if type1.Equals(type2) {
648+
return true
649+
}
650+
651+
t1 := type1.Type()
652+
t2 := type2.Type()
653+
654+
// Handle same-type cases for special types
655+
if t1 == t2 {
656+
switch t1 {
657+
case sqltypes.Enum:
658+
// Enum types can reference each other in foreign keys regardless of their string values.
659+
// MySQL allows enum foreign keys to match based on underlying numeric values.
660+
return true
661+
case sqltypes.Decimal:
662+
// MySQL allows decimal foreign keys with different precision/scale
663+
// The foreign key constraint validation will handle the actual value comparison
664+
return true
665+
case sqltypes.Set:
666+
// MySQL allows set foreign keys to match based on underlying numeric values.
667+
return true
674668
}
675669
}
676-
return true
670+
671+
// Handle string types (both same-type with different lengths and mixed types)
672+
if (types.IsTextOnly(type1) && types.IsTextOnly(type2)) ||
673+
(types.IsBinaryType(type1) && types.IsBinaryType(type2)) {
674+
// String types must have matching character sets
675+
type1String := type1.(sql.StringType)
676+
type2String := type2.(sql.StringType)
677+
return type1String.Collation().CharacterSet() == type2String.Collation().CharacterSet()
678+
}
679+
680+
return false
677681
}
678682

679683
// exprsAreIndexPrefix returns whether the given expressions are a prefix of the given index expressions

0 commit comments

Comments
 (0)