Document significance of preproces_schema method
[dbsrgits/SQL-Translator.git] / lib / SQL / Translator / Producer / MySQL.pm
index 6c20e56..9b65bb7 100644 (file)
@@ -126,7 +126,7 @@ my %translate  = (
 
 
 sub preprocess_schema {
-    my ($class, $schema) = @_;
+    my ($schema) = @_;
 
     # extra->{mysql_table_type} used to be the type. It belongs in options, so
     # move it if we find it. Return Engine type if found in extra or options
@@ -178,7 +178,7 @@ sub preprocess_schema {
        
         $mysql_table_type_to_options->($table);
 
-        foreach my $c( $table->get_constraints ) {
+        foreach my $c ( $table->get_constraints ) {
             next unless $c->type eq FOREIGN_KEY;
 
             # Normalize constraint names here.
@@ -194,7 +194,15 @@ sub preprocess_schema {
                 next if $mysql_table_type_to_options->($table);
                 $table->options( { 'ENGINE' => 'InnoDB' } );
             }
+        } # foreach constraints
+
+        foreach my $f ( $table->get_fields ) {
+          my @size = $f->size;
+          if ( !$size[0] && $f->data_type =~ /char$/ ) {
+            $f->size( (255) );
+          }
         }
+
     }
 }
 
@@ -218,7 +226,7 @@ sub produce {
     # \todo Don't set if MySQL 3.x is set on command line
     $create .= "SET foreign_key_checks=0;\n\n";
 
-    __PACKAGE__->preprocess_schema($schema);
+    preprocess_schema($schema);
 
     #
     # Generate sql
@@ -379,9 +387,6 @@ sub create_field
         $data_type = 'text';
         @size      = ();
     }
-    elsif ( $data_type =~ /char/i && ! $size[0] ) {
-        @size = (255);
-    }
     elsif ( $data_type =~ /boolean/i ) {
         $data_type = 'enum';
         $commalist = "'0','1'";
@@ -655,12 +660,43 @@ sub drop_field
 sub batch_alter_table {
   my ($table, $diff_hash, $options) = @_;
 
+  # InnoDB has an issue with dropping and re-adding a FK constraint under the 
+  # name in a single alter statment, see: http://bugs.mysql.com/bug.php?id=13741
+  #
+  # We have to work round this.
+
+  my %fks_to_alter;
+  my %fks_to_drop = map {
+    $_->type eq FOREIGN_KEY 
+              ? ( $_->name => $_ ) 
+              : ( )
+  } @{$diff_hash->{alter_drop_constraint} };
+
+  my %fks_to_create = map {
+    if ( $_->type eq FOREIGN_KEY) {
+      $fks_to_alter{$_->name} = $fks_to_drop{$_->name} if $fks_to_drop{$_->name};
+      ( $_->name => $_ );
+    } else { ( ) }
+  } @{$diff_hash->{alter_create_constraint} };
+
+  my $drop_stmt = '';
+  if (scalar keys %fks_to_alter) {
+    $diff_hash->{alter_drop_constraint} = [
+      grep { !$fks_to_alter{$_->name} } @{ $diff_hash->{alter_drop_constraint} }
+    ];
+
+    $drop_stmt = batch_alter_table($table, { alter_drop_constraint => [ values %fks_to_alter ] }, $options) 
+               . "\n";
+
+  }
+
   my @stmts = map {
     if (@{ $diff_hash->{$_} || [] }) {
       my $meth = __PACKAGE__->can($_) or die __PACKAGE__ . " cant $_";
-      map { $meth->(ref $_ eq 'ARRAY' ? @$_ : $_) } @{ $diff_hash->{$_} }
+      map { $meth->( (ref $_ eq 'ARRAY' ? @$_ : $_), $options ) } @{ $diff_hash->{$_} }
     } else { () }
-  } qw/alter_drop_constraint
+  } qw/rename_table
+       alter_drop_constraint
        alter_drop_index
        drop_field
        add_field
@@ -670,31 +706,52 @@ sub batch_alter_table {
        alter_create_constraint
        alter_table/;
 
+  # rename_table makes things a bit more complex
+  my $renamed_from = "";
+  $renamed_from = $diff_hash->{rename_table}[0][0]->name
+    if $diff_hash->{rename_table} && @{$diff_hash->{rename_table}};
+
   return unless @stmts;
   # Just zero or one stmts. return now
-  return "@stmts;" unless @stmts > 1;
+  return "$drop_stmt@stmts;" unless @stmts > 1;
 
   # Now strip off the 'ALTER TABLE xyz' of all but the first one
 
   my $qt = $options->{quote_table_name} || '';
   my $table_name = $qt . $table->name . $qt;
 
+
+  my $re = $renamed_from 
+         ? qr/^ALTER TABLE (?:\Q$table_name\E|\Q$qt$renamed_from$qt\E) /
+            : qr/^ALTER TABLE \Q$table_name\E /;
+
   my $first = shift  @stmts;
-  my ($alter_table) = $first =~ /^(ALTER TABLE \Q$table_name\E )/;
-  my $re = qr/^$alter_table/;
+  my ($alter_table) = $first =~ /($re)/;
+
   my $padd = " " x length($alter_table);
 
-  return join( ",\n", $first, map { s/$re//; $padd . $_ } @stmts) . ';';
+  return $drop_stmt . join( ",\n", $first, map { s/$re//; $padd . $_ } @stmts) . ';';
+
 }
 
 sub drop_table {
-  my ($table) = @_;
+  my ($table, $options) = @_;
+
+    my $qt = $options->{quote_table_names} || '';
 
   # Drop (foreign key) constraints so table drops cleanly
-  my @sql = batch_alter_table($table, { alter_drop_constraint => [ grep { $_->type eq 'FOREIGN KEY' } $table->get_constraints ] });
+  my @sql = batch_alter_table($table, { alter_drop_constraint => [ grep { $_->type eq 'FOREIGN KEY' } $table->get_constraints ] }, $options);
+
+  return join("\n", @sql, "DROP TABLE $qt$table$qt;");
+
+}
+
+sub rename_table {
+  my ($old_table, $new_table, $options) = @_;
 
-  return join("\n", @sql, "DROP TABLE $table;");
+  my $qt = $options->{quote_table_names} || '';
 
+  return "ALTER TABLE $qt$old_table$qt RENAME TO $qt$new_table$qt";
 }
 
 sub next_unused_name {