my $target_schema = $self->target_schema;
my $source_schema = $self->source_schema;
+ my $producer_class = "SQL::Translator::Producer::@{[$self->output_db]}";
+ eval "require $producer_class";
+ die $@ if $@;
+
+ if (my $preprocess = $producer_class->can('preprocess_schema')) {
+ $producer_class->$preprocess($source_schema);
+ $DB::single = 1;
+ $producer_class->$preprocess($target_schema);
+ }
+
my @tar_tables = sort { $a->name cmp $b->name } $target_schema->get_tables;
## do original/source tables exist in target?
for my $tar_table ( @tar_tables ) {
my $tar_table_name = $tar_table->name;
+ $DB::single = 1 if $tar_table_name eq 'admin_contest';
my $src_table = $source_schema->get_table( $tar_table_name, $self->case_insensitive );
unless ( $src_table ) {
for my $tar_table_field ( $tar_table->get_fields ) {
my $f_tar_name = $tar_table_field->name;
+ $DB::single = 1 if $f_tar_name eq 'invite_type';
if (my $old_name = $tar_table_field->extra->{renamed_from}) {
my $src_table_field = $src_table->get_field( $old_name, $self->case_insensitive );
die qq#Renamed cant find "@{[$src_table->name]}.$old_name" for renamed column\n# unless $src_table_field;
my ($self, $src_table, $tar_table) = @_;
- # Go through our options
- my $options_different = 0;
- my %checkedOptions;
-
- OPTION:
- for my $tar_table_option_ref ( $tar_table->options ) {
- my($key_tar, $value_tar) = %{$tar_table_option_ref};
- for my $src_table_option_ref ( $src_table->options ) {
- my($key_src, $value_src) = %{$src_table_option_ref};
- if ( $key_tar eq $key_src ) {
- if ( defined $value_tar != defined $value_src ) {
- $options_different = 1;
- last OPTION;
- }
- if ( defined $value_tar && $value_tar ne $value_src ) {
- $options_different = 1;
- last OPTION;
- }
- $checkedOptions{$key_tar} = 1;
- next OPTION;
- }
- }
- $options_different = 1;
- last OPTION;
- }
-
- # Go through the other table's options
- unless ( $options_different ) {
- for my $src_table_option_ref ( $src_table->options ) {
- my($key, $value) = %{$src_table_option_ref};
- next if $checkedOptions{$key};
- $options_different = 1;
- last;
- }
- }
-
# If there's a difference, just re-set all the options
push @{ $self->table_diff_hash->{$tar_table}{table_options} }, $tar_table
- if ( $options_different );
+ unless $src_table->_compare_objects( scalar $src_table->options, scalar $tar_table->options );
}
1;
use base qw(Exporter);
our %type_mapping = (
- int => SQL_INTEGER,
- integer => SQL_INTEGER,
-
- tinyint => SQL_TINYINT,
- smallint => SQL_SMALLINT,
- mediumint,
- bigint,
-
- float => SQL_FLOAT, # Precision 0..23
- double => SQL_DOUBLE, # Precision 24..53
- "double precision" => SQL_DOUBLE,
- real => SQL_DOUBLE,
-
- # all these are the same.
- decimal => SQL_DECIMAL,
- numeric => SQL_NUMERIC,
- dec => SQL_DECIMAL,
- # fixed: does this exist
-
- bit => SQL_BIT
-
- date => SQL_DATE,
- datetime => SQL_DATETIME,
- timestamp => SQL_TIMESTAMP,
- time => SQL_TIME,
- year
-
-
- char => SQL_CHAR,
- varchar => SQL_VARCHAR,
- binary => SQL_BINARY,
- varbinary => SQL_VARBINARY,
- tinyblob => SQL_BLOB,
- tinytext =>
- blob => SQL_BLOB,
- text => SQL_LONGVARCHAR
- mediumblob => SQL_BLOB,
- mediumtext => SQL_LONGVARCHAR
- longblob => SQL_BLOB
- longtext => SQL_LONGVARCHAR
-
- enum
- set
);
@EXPORT_OK = qw(parse);
) or die $table->error;
}
- if ( $field->data_type =~ /(set|enum)/i && !$field->size ) {
- my %extra = $field->extra;
- my $longest = 0;
- for my $len ( map { length } @{ $extra{'list'} || [] } ) {
- $longest = $len if $len > $longest;
- }
- $field->size( $longest ) if $longest;
- }
-
for my $cdata ( @{ $fdata->{'constraints'} } ) {
next unless $cdata->{'type'} eq 'foreign_key';
$cdata->{'fields'} ||= [ $field->name ];
$changed = $size != 4_294_967_295;
$size = 4_294_967_295;
}
- $DB::single = 1 if $field->name eq 'employee_id';
+ if ( $field->data_type =~ /(set|enum)/i && !$field->size ) {
+ my %extra = $field->extra;
+ my $longest = 0;
+ for my $len ( map { length } @{ $extra{'list'} || [] } ) {
+ $longest = $len if $len > $longest;
+ }
+ $changed = 1;
+ $size = $longest if $longest;
+ }
+
+
if ($changed) {
# We only want to clone the field, not *everything*
{ local $field->{table} = undef;
}
$field->size($size);
$field->data_type($type);
- $field->sql_data_type( $type_mapping{lc $type} || SQL_UNKNOWN_TYPE );
+ $field->sql_data_type( $type_mapping{lc $type} ) if exists $type_mapping{lc $type};
$field->extra->{list} = $list if @$list;
}
}
'datetime' => 'datetime',
);
+
+sub preprocess_schema {
+ my ($class, $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
+ my $mysql_table_type_to_options = sub {
+ my ($table) = @_;
+
+ my $extra = $table->extra;
+
+ my $extra_type = delete $extra->{mysql_table_type};
+
+ # Now just to find if there is already an Engine or Type option...
+ # and lets normalize it to ENGINE since:
+ #
+ # The ENGINE table option specifies the storage engine for the table.
+ # TYPE is a synonym, but ENGINE is the preferred option name.
+ #
+
+ # We have to use the hash directly here since otherwise there is no way
+ # to remove options.
+ my $options = ( $table->{options} ||= []);
+
+ # This assumes that there isn't both a Type and an Engine option.
+ for my $idx ( 0..$#{$options} ) {
+ my ($key, $value) = %{ $options->[$idx] };
+
+ next unless uc $key eq 'ENGINE' || uc $key eq 'TYPE';
+
+ # if the extra.mysql_table_type is given, use that
+ delete $options->[$idx]{$key};
+ return $options->[$idx]{ENGINE} = $value || $extra_type;
+
+ }
+
+ if ($extra_type) {
+ push @$options, { ENGINE => $extra_type };
+ return $extra_type;
+ }
+
+ };
+
+ #
+ # Work out which tables need to be InnoDB to support foreign key
+ # constraints. We do this first as we need InnoDB at both ends.
+ #
+ foreach my $table ( $schema->get_tables ) {
+
+ $mysql_table_type_to_options->($table);
+
+ foreach ( $table->get_constraints ) {
+ next unless $_->type eq FOREIGN_KEY;
+ for my $meth (qw/table reference_table/) {
+ my $table = $schema->get_table($_->$meth) || next;
+ next if $mysql_table_type_to_options->($table);
+ $table->options( { 'ENGINE' => 'InnoDB' } );
+ }
+ }
+ }
+}
+
sub produce {
my $translator = shift;
local $DEBUG = $translator->debug;
# \todo Don't set if MySQL 3.x is set on command line
$create .= "SET foreign_key_checks=0;\n\n";
- #
- # Work out which tables need to be InnoDB to support foreign key
- # constraints. We do this first as we need InnoDB at both ends.
- #
- foreach ( map { $_->get_constraints } $schema->get_tables ) {
- next unless $_->type eq FOREIGN_KEY;
- foreach my $meth (qw/table reference_table/) {
- my $table = $schema->get_table($_->$meth) || next;
- next if $table->extra('mysql_table_type');
- $table->extra( 'mysql_table_type' => 'InnoDB');
- }
- }
+ __PACKAGE__->preprocess_schema($schema);
#
# Generate sql
if uc $key eq 'ENGINE' or uc $key eq 'TYPE';
$create .= " $key=$value";
}
+
my $mysql_table_type = $table->extra('mysql_table_type');
- $create .= " Type=$mysql_table_type"
+ $create .= " ENGINE=$mysql_table_type"
if $mysql_table_type && !$table_type_defined;
my $charset = $table->extra('mysql_charset');
my $collate = $table->extra('mysql_collate');
fallback => 1,
;
+use DBI qw(:sql_types);
+
+# Mapping from string to sql contstant
+our %type_mapping = (
+ integer => SQL_INTEGER,
+ int => SQL_INTEGER,
+
+ smallint => SQL_SMALLINT,
+ bigint => 9999, # DBI doesn't export a constatn for this. Le suck
+
+ double => SQL_DOUBLE,
+
+ decimal => SQL_DECIMAL,
+ numeric => SQL_NUMERIC,
+ dec => SQL_DECIMAL,
+
+ bit => SQL_BIT,
+
+ date => SQL_DATE,
+ datetime => SQL_DATETIME,
+ timestamp => SQL_TIMESTAMP,
+ time => SQL_TIME,
+
+ char => SQL_CHAR,
+ varchar => SQL_VARCHAR,
+ binary => SQL_BINARY,
+ varbinary => SQL_VARBINARY,
+ tinyblob => SQL_BLOB,
+ blob => SQL_BLOB,
+ text => SQL_LONGVARCHAR
+
+);
# ----------------------------------------------------------------------
__PACKAGE__->_attributes( qw/
=cut
my $self = shift;
- $self->{'data_type'} = shift if @_;
+ if (@_) {
+ $self->{'data_type'} = $_[0];
+ $self->{'sql_data_type'} = $type_mapping{lc $_[0]} || SQL_UNKNOWN_TYPE unless exists $self->{sql_data_type};
+ }
return $self->{'data_type'} || '';
}
`description` text CHARACTER SET utf8 COLLATE utf8_general_ci,
PRIMARY KEY (`id`),
UNIQUE `idx_unique_name` (`name`)
-) Type=InnoDB DEFAULT CHARACTER SET latin1 COLLATE latin1_danish_ci;\n\n",
+) ENGINE=InnoDB DEFAULT CHARACTER SET latin1 COLLATE latin1_danish_ci;\n\n",
"DROP TABLE IF EXISTS `thing2`;\n",
"CREATE TABLE `thing2` (
PRIMARY KEY (`id`, `foo`),
CONSTRAINT `fk_thing` FOREIGN KEY (`foo`) REFERENCES `thing` (`id`),
CONSTRAINT `fk_thing_1` FOREIGN KEY (`foo2`) REFERENCES `thing` (`id`)
-) Type=InnoDB;\n\n",
+) ENGINE=InnoDB;\n\n",
"SET foreign_key_checks=1;\n\n"