handle MySQL enums/sets containing elements with single quotes
[dbsrgits/DBIx-Class-Schema-Loader.git] / lib / DBIx / Class / Schema / Loader / DBI / mysql.pm
index 3524cea..cb83e7a 100644 (file)
@@ -3,33 +3,28 @@ package DBIx::Class::Schema::Loader::DBI::mysql;
 use strict;
 use warnings;
 use base 'DBIx::Class::Schema::Loader::DBI';
-use Carp::Clan qw/^DBIx::Class/;
 use mro 'c3';
+use List::Util 'first';
+use namespace::clean;
 
-our $VERSION = '0.07001';
+our $VERSION = '0.07010';
 
 =head1 NAME
 
 DBIx::Class::Schema::Loader::DBI::mysql - DBIx::Class::Schema::Loader::DBI mysql Implementation.
 
-=head1 SYNOPSIS
-
-  package My::Schema;
-  use base qw/DBIx::Class::Schema::Loader/;
-
-  __PACKAGE__->loader_options( debug => 1 );
-
-  1;
-
 =head1 DESCRIPTION
 
-See L<DBIx::Class::Schema::Loader::Base>.
+See L<DBIx::Class::Schema::Loader> and L<DBIx::Class::Schema::Loader::Base>.
 
 =cut
 
 sub _setup {
     my $self = shift;
 
+    $self->schema->storage->sql_maker->quote_char("`");
+    $self->schema->storage->sql_maker->name_sep(".");
+
     $self->next::method(@_);
 
     if (not defined $self->preserve_case) {
@@ -71,10 +66,12 @@ sub _table_fk_info {
         my @f_cols = map { s/(?: \Q$self->{_quoter}\E | $qt )//x; $self->_lc($_) }
             split(/$qt?\s*$qt?,$qt?\s*$qt?/, $f_cols);
 
+        my $remote_table = first { $_ =~ /^${f_table}\z/i } $self->_tables_list;
+
         push(@rels, {
             local_columns => \@cols,
             remote_columns => \@f_cols,
-            remote_table => $f_table
+            remote_table => $remote_table,
         });
     }
 
@@ -136,14 +133,15 @@ sub _columns_info_for {
     my $dbh = $self->schema->storage->dbh;
 
     while (my ($col, $info) = each %$result) {
-        delete $info->{size} if $info->{data_type} !~ /^(?: (?:var)?(?:char(?:acter)?|binary) | bit | year)\z/ix;
-
         if ($info->{data_type} eq 'int') {
             $info->{data_type} = 'integer';
         }
         elsif ($info->{data_type} eq 'double') {
             $info->{data_type} = 'double precision';
         }
+        my $data_type = $info->{data_type};
+
+        delete $info->{size} if $data_type !~ /^(?: (?:var)?(?:char(?:acter)?|binary) | bit | year)\z/ix;
 
         # information_schema is available in 5.0+
         my ($precision, $scale, $column_type, $default) = eval { $dbh->selectrow_array(<<'EOF', {}, $table, $col) };
@@ -151,14 +149,14 @@ SELECT numeric_precision, numeric_scale, column_type, column_default
 FROM information_schema.columns
 WHERE table_name = ? AND column_name = ?
 EOF
-        my $has_information_schema = not defined $@;
+        my $has_information_schema = not $@;
 
         $column_type = '' if not defined $column_type;
 
-        if ($info->{data_type} eq 'bit' && (not exists $info->{size})) {
+        if ($data_type eq 'bit' && (not exists $info->{size})) {
             $info->{size} = $precision if defined $precision;
         }
-        elsif ($info->{data_type} =~ /^(?:float|double precision|decimal)\z/i) {
+        elsif ($data_type =~ /^(?:float|double precision|decimal)\z/i) {
             if (defined $precision && defined $scale) {
                 if ($precision == 10 && $scale == 0) {
                     delete $info->{size};
@@ -168,7 +166,7 @@ EOF
                 }
             }
         }
-        elsif ($info->{data_type} eq 'year') {
+        elsif ($data_type eq 'year') {
             if ($column_type =~ /\(2\)/) {
                 $info->{size} = 2;
             }
@@ -176,6 +174,22 @@ EOF
                 delete $info->{size};
             }
         }
+        elsif ($data_type =~ /^(?:date(?:time)?|timestamp)\z/) {
+            if (not (defined $self->datetime_undef_if_invalid && $self->datetime_undef_if_invalid == 0)) {
+                $info->{datetime_undef_if_invalid} = 1;
+            }
+        }
+        elsif ($data_type =~ /^(?:enum|set)\z/ && $has_information_schema
+               && $column_type =~ /^(?:enum|set)\(/) {
+
+            delete $info->{extra}{list};
+
+            while ($column_type =~ /'((?:[^']* (?:''|\\')* [^']*)* [^\\'])',?/xg) {
+                my $el = $1;
+                $el =~ s/''/'/g;
+                push @{ $info->{extra}{list} }, $el;
+            }
+        }
 
         # Sometimes apparently there's a bug where default_value gets set to ''
         # for things that don't actually have or support that default (like ints.)
@@ -186,7 +200,7 @@ EOF
                 }
             }
             else { # just check if it's a char/text type, otherwise remove
-                delete $info->{default_value} unless $info->{data_type} =~ /char|text/i;
+                delete $info->{default_value} unless $data_type =~ /char|text/i;
             }
         }
     }
@@ -218,6 +232,15 @@ sub _extra_column_info {
     return \%extra_info;
 }
 
+sub _dbh_column_info {
+    my $self = shift;
+
+    local $SIG{__WARN__} = sub { warn @_
+        unless $_[0] =~ /^column_info: unrecognized column type/ };
+
+    $self->next::method(@_);
+}
+
 =head1 SEE ALSO
 
 L<DBIx::Class::Schema::Loader>, L<DBIx::Class::Schema::Loader::Base>,