Constraint/index name fix from rdj
[dbsrgits/DBIx-Class.git] / lib / SQL / Translator / Parser / DBIx / Class.pm
index dc18bbb..1b6266f 100644 (file)
@@ -14,6 +14,7 @@ $DEBUG = 0 unless defined $DEBUG;
 
 use Exporter;
 use Data::Dumper;
+use Digest::SHA1 qw( sha1_hex );
 use SQL::Translator::Utils qw(debug normalize_name);
 
 use base qw(Exporter);
@@ -107,13 +108,12 @@ sub parse {
             if (!$source->compare_relationship_keys($unique_constraints{$uniq}, \@primary)) {
                 $table->add_constraint(
                             type             => 'unique',
-                            name             => "$uniq",
+                            name             => _create_unique_symbol($uniq),
                             fields           => $unique_constraints{$uniq}
                 );
 
                my $index = $table->add_index(
-                            # TODO: Pick a better than that wont conflict
-                            name   => $unique_constraints{$uniq}->[0],
+                            name   => _create_unique_symbol(join('_', @{$unique_constraints{$uniq}})),
                             fields => $unique_constraints{$uniq},
                             type   => 'NORMAL',
                );
@@ -179,7 +179,9 @@ sub parse {
                 if (scalar(@keys)) {
                   $table->add_constraint(
                                     type             => 'foreign_key',
-                                    name             => $table->name . "_fk_$keys[0]",
+                                    name             => _create_unique_symbol($table->name
+                                                                            . '_fk_'
+                                                                            . join('_', @keys)),
                                     fields           => \@keys,
                                     reference_fields => \@refkeys,
                                     reference_table  => $rel_table,
@@ -189,7 +191,7 @@ sub parse {
                   );
                     
                   my $index = $table->add_index(
-                                    name   => join('_', @keys),
+                                    name   => _create_unique_symbol(join('_', @keys)),
                                     fields => \@keys,
                                     type   => 'NORMAL',
                   );
@@ -209,5 +211,31 @@ sub parse {
     return 1;
 }
 
-1;
+# TODO - is there a reasonable way to pass configuration?
+# Default of 64 comes from mysql's limit.
+our $MAX_SYMBOL_LENGTH    ||= 64;
+our $COLLISION_TAG_LENGTH ||= 8;
+
+# -------------------------------------------------------------------
+# $resolved_name = _create_unique_symbol($desired_name)
+#
+# If desired_name is really long, it will be truncated in a way that
+# has a high probability of leaving it unique.
+# -------------------------------------------------------------------
+sub _create_unique_symbol {
+    my $desired_name = shift;
+    return $desired_name if length $desired_name <= $MAX_SYMBOL_LENGTH;
 
+    my $truncated_name = substr $desired_name, 0, $MAX_SYMBOL_LENGTH - $COLLISION_TAG_LENGTH - 1;
+
+    # Hex isn't the most space-efficient, but it skirts around allowed
+    # charset issues
+    my $digest = sha1_hex($desired_name);
+    my $collision_tag = substr $digest, 0, $COLLISION_TAG_LENGTH;
+
+    return $truncated_name
+         . '_'
+         . $collision_tag;
+}
+
+1;