Skip to content

Commit c8c8b78

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 4489623 commit c8c8b78

File tree

1 file changed

+32
-56
lines changed

1 file changed

+32
-56
lines changed

sql/plan/alter_foreign_key.go

Lines changed: 32 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -644,71 +644,47 @@ 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-
default:
667-
return false
668-
}
669-
} else {
670-
// MySQL allows mixed string types in foreign key constraints:
671-
// - CHAR can reference VARCHAR and vice versa
672-
// - BINARY can reference VARBINARY and vice versa
673-
if compatibleStringTypes(type1, type2) {
674-
type1String := type1.(sql.StringType)
675-
type2String := type2.(sql.StringType)
676-
if type1String.Collation().CharacterSet() != type2String.Collation().CharacterSet() {
677-
return false
678-
}
679-
} else {
680-
return false
681-
}
682-
}
647+
if type1.Equals(type2) {
648+
return true
683649
}
684-
return true
685-
}
686650

687-
// compatibleStringTypes checks if two different string types are compatible for foreign key constraints.
688-
// MySQL allows mixed string types within the same category:
689-
// - Character types: CHAR and VARCHAR
690-
// - Binary types: BINARY and VARBINARY
691-
func compatibleStringTypes(type1 sql.Type, type2 sql.Type) bool {
692-
if type1 == nil || type2 == nil {
693-
return false
694-
}
695-
696651
t1 := type1.Type()
697652
t2 := type2.Type()
698-
699-
// Check if both are character string types (CHAR/VARCHAR)
700-
if (t1 == sqltypes.Char || t1 == sqltypes.VarChar) && (t2 == sqltypes.Char || t2 == sqltypes.VarChar) {
701-
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+
default:
672+
return false
673+
}
702674
}
703-
704-
// Check if both are binary string types (BINARY/VARBINARY)
705-
if (t1 == sqltypes.Binary || t1 == sqltypes.VarBinary) && (t2 == sqltypes.Binary || t2 == sqltypes.VarBinary) {
706-
return true
675+
676+
// Mixed string types: CHAR/VARCHAR or BINARY/VARBINARY
677+
if ((t1 == sqltypes.Char || t1 == sqltypes.VarChar) && (t2 == sqltypes.Char || t2 == sqltypes.VarChar)) ||
678+
((t1 == sqltypes.Binary || t1 == sqltypes.VarBinary) && (t2 == sqltypes.Binary || t2 == sqltypes.VarBinary)) {
679+
type1String := type1.(sql.StringType)
680+
type2String := type2.(sql.StringType)
681+
return type1String.Collation().CharacterSet() == type2String.Collation().CharacterSet()
707682
}
708-
683+
709684
return false
710685
}
711686

687+
712688
// exprsAreIndexPrefix returns whether the given expressions are a prefix of the given index expressions
713689
func exprsAreIndexPrefix(exprs, indexExprs []string) bool {
714690
if len(exprs) > len(indexExprs) {

0 commit comments

Comments
 (0)