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
$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.
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) );
+ }
}
+
}
}
# \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
$data_type = 'text';
@size = ();
}
- elsif ( $data_type =~ /char/i && ! $size[0] ) {
- @size = (255);
- }
elsif ( $data_type =~ /boolean/i ) {
$data_type = 'enum';
$commalist = "'0','1'";
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
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 {