Skip to content

Commit 2b7ab56

Browse files
elianddbclaude
andcommitted
Clean up mixed string foreign key logic
Refactor foreignKeyComparableTypes function to improve readability: - Inline compatibleStringTypes function for locality of behavior - Compress logic while preserving legacy structure - Combine duplicate charset validation logic - Maintain important comments explaining MySQL behavior 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
1 parent c33a07d commit 2b7ab56

File tree

1 file changed

+35
-59
lines changed

1 file changed

+35
-59
lines changed

sql/plan/alter_foreign_key.go

Lines changed: 35 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -644,74 +644,50 @@ 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-
// MySQL allows mixed string types in foreign key constraints:
674-
// - CHAR can reference VARCHAR and vice versa
675-
// - BINARY can reference VARBINARY and vice versa
676-
if compatibleStringTypes(type1, type2) {
677-
type1String := type1.(sql.StringType)
678-
type2String := type2.(sql.StringType)
679-
if type1String.Collation().CharacterSet() != type2String.Collation().CharacterSet() {
680-
return false
681-
}
682-
} else {
683-
return false
684-
}
685-
}
647+
if type1.Equals(type2) {
648+
return true
686649
}
687-
return true
688-
}
689650

690-
// compatibleStringTypes checks if two different string types are compatible for foreign key constraints.
691-
// MySQL allows mixed string types within the same category:
692-
// - Character types: CHAR and VARCHAR
693-
// - Binary types: BINARY and VARBINARY
694-
func compatibleStringTypes(type1 sql.Type, type2 sql.Type) bool {
695-
if type1 == nil || type2 == nil {
696-
return false
697-
}
698-
699651
t1 := type1.Type()
700652
t2 := type2.Type()
701-
702-
// Check if both are character string types (CHAR/VARCHAR)
703-
if (t1 == sqltypes.Char || t1 == sqltypes.VarChar) && (t2 == sqltypes.Char || t2 == sqltypes.VarChar) {
704-
return true
653+
654+
// Same type with different parameters
655+
if t1 == t2 {
656+
switch t1 {
657+
case sqltypes.Char, sqltypes.VarChar, sqltypes.Binary, sqltypes.VarBinary:
658+
// There seems to be a special case where CHAR/VARCHAR/BINARY/VARBINARY can have unequal lengths.
659+
// Have not tested every type nor combination, but this seems specific to those 4 types.
660+
type1String := type1.(sql.StringType)
661+
type2String := type2.(sql.StringType)
662+
return type1String.Collation().CharacterSet() == type2String.Collation().CharacterSet()
663+
case sqltypes.Enum:
664+
// Enum types can reference each other in foreign keys regardless of their string values.
665+
// MySQL allows enum foreign keys to match based on underlying numeric values.
666+
return true
667+
case sqltypes.Decimal:
668+
// MySQL allows decimal foreign keys with different precision/scale
669+
// The foreign key constraint validation will handle the actual value comparison
670+
return true
671+
case sqltypes.Set:
672+
// MySQL allows set foreign keys to match based on underlying numeric values.
673+
return true
674+
default:
675+
return false
676+
}
705677
}
706-
707-
// Check if both are binary string types (BINARY/VARBINARY)
708-
if (t1 == sqltypes.Binary || t1 == sqltypes.VarBinary) && (t2 == sqltypes.Binary || t2 == sqltypes.VarBinary) {
709-
return true
678+
679+
// Mixed string types: CHAR/VARCHAR or BINARY/VARBINARY
680+
if ((t1 == sqltypes.Char || t1 == sqltypes.VarChar) && (t2 == sqltypes.Char || t2 == sqltypes.VarChar)) ||
681+
((t1 == sqltypes.Binary || t1 == sqltypes.VarBinary) && (t2 == sqltypes.Binary || t2 == sqltypes.VarBinary)) {
682+
type1String := type1.(sql.StringType)
683+
type2String := type2.(sql.StringType)
684+
return type1String.Collation().CharacterSet() == type2String.Collation().CharacterSet()
710685
}
711-
686+
712687
return false
713688
}
714689

690+
715691
// exprsAreIndexPrefix returns whether the given expressions are a prefix of the given index expressions
716692
func exprsAreIndexPrefix(exprs, indexExprs []string) bool {
717693
if len(exprs) > len(indexExprs) {

0 commit comments

Comments
 (0)