fix loading MySQL views on older MySQL versions (RT#47399)
[dbsrgits/DBIx-Class-Schema-Loader.git] / lib / DBIx / Class / Schema / Loader / DBI / mysql.pm
CommitLineData
996be9ee 1package DBIx::Class::Schema::Loader::DBI::mysql;
2
3use strict;
4use warnings;
5use base 'DBIx::Class::Schema::Loader::DBI';
fa994d3c 6use Carp::Clan qw/^DBIx::Class/;
996be9ee 7use Class::C3;
8
5afd3e72 9our $VERSION = '0.06001';
32f784fc 10
996be9ee 11=head1 NAME
12
13DBIx::Class::Schema::Loader::DBI::mysql - DBIx::Class::Schema::Loader::DBI mysql Implementation.
14
15=head1 SYNOPSIS
16
17 package My::Schema;
18 use base qw/DBIx::Class::Schema::Loader/;
19
59cfa251 20 __PACKAGE__->loader_options( debug => 1 );
996be9ee 21
22 1;
23
24=head1 DESCRIPTION
25
26See L<DBIx::Class::Schema::Loader::Base>.
27
28=cut
29
518472fa 30sub _tables_list {
bfb43060 31 my ($self, $opts) = @_;
518472fa 32
bfb43060 33 return $self->next::method($opts, undef, undef);
518472fa 34}
35
996be9ee 36sub _table_fk_info {
37 my ($self, $table) = @_;
38
5223f24a 39 my $dbh = $self->schema->storage->dbh;
3de915bc 40
41 local $dbh->{RaiseError} = 0;
42 local $dbh->{PrintError} = 0;
43
44 my $table_def_ref = eval { $dbh->selectrow_arrayref("SHOW CREATE TABLE `$table`") };
45 my $table_def = $table_def_ref->[1];
46
47 return [] if not $table_def;
309e2aa1 48
49 my $qt = qr/["`]/;
50
51 my (@reldata) = ($table_def =~
52 /CONSTRAINT $qt.*$qt FOREIGN KEY \($qt(.*)$qt\) REFERENCES $qt(.*)$qt \($qt(.*)$qt\)/ig
53 );
996be9ee 54
55 my @rels;
56 while (scalar @reldata > 0) {
57 my $cols = shift @reldata;
58 my $f_table = shift @reldata;
59 my $f_cols = shift @reldata;
60
309e2aa1 61 my @cols = map { s/(?: \Q$self->{_quoter}\E | $qt )//x; lc $_ }
5223f24a 62 split(/\s*,\s*/, $cols);
63
309e2aa1 64 my @f_cols = map { s/(?: \Q$self->{_quoter}\E | $qt )//x; lc $_ }
5223f24a 65 split(/\s*,\s*/, $f_cols);
996be9ee 66
67 push(@rels, {
68 local_columns => \@cols,
69 remote_columns => \@f_cols,
70 remote_table => $f_table
71 });
72 }
73
74 return \@rels;
75}
76
77# primary and unique info comes from the same sql statement,
78# so cache it here for both routines to use
79sub _mysql_table_get_keys {
80 my ($self, $table) = @_;
81
5223f24a 82 if(!exists($self->{_cache}->{_mysql_keys}->{$table})) {
996be9ee 83 my %keydata;
84 my $dbh = $self->schema->storage->dbh;
075aff97 85 my $sth = $dbh->prepare('SHOW INDEX FROM '.$self->_table_as_sql($table));
996be9ee 86 $sth->execute;
87 while(my $row = $sth->fetchrow_hashref) {
88 next if $row->{Non_unique};
89 push(@{$keydata{$row->{Key_name}}},
90 [ $row->{Seq_in_index}, lc $row->{Column_name} ]
91 );
92 }
93 foreach my $keyname (keys %keydata) {
94 my @ordered_cols = map { $_->[1] } sort { $a->[0] <=> $b->[0] }
95 @{$keydata{$keyname}};
96 $keydata{$keyname} = \@ordered_cols;
97 }
5223f24a 98 $self->{_cache}->{_mysql_keys}->{$table} = \%keydata;
996be9ee 99 }
100
5223f24a 101 return $self->{_cache}->{_mysql_keys}->{$table};
996be9ee 102}
103
104sub _table_pk_info {
105 my ( $self, $table ) = @_;
106
107 return $self->_mysql_table_get_keys($table)->{PRIMARY};
108}
109
110sub _table_uniq_info {
111 my ( $self, $table ) = @_;
112
113 my @uniqs;
114 my $keydata = $self->_mysql_table_get_keys($table);
8ac8926d 115 foreach my $keyname (keys %$keydata) {
996be9ee 116 next if $keyname eq 'PRIMARY';
117 push(@uniqs, [ $keyname => $keydata->{$keyname} ]);
118 }
119
120 return \@uniqs;
121}
122
26334ec1 123sub _columns_info_for {
124 my $self = shift;
125 my ($table) = @_;
126
127 my $result = $self->next::method(@_);
128
129 my $dbh = $self->schema->storage->dbh;
130
131 while (my ($col, $info) = each %$result) {
132 delete $info->{size}
133 unless $info->{data_type} =~ /^(?: (?:var)?(?:char(?:acter)?|binary) | bit | year)\z/ix;
134
135 if ($info->{data_type} eq 'int') {
136 $info->{data_type} = 'integer';
137 }
138 elsif ($info->{data_type} eq 'double') {
139 $info->{data_type} = 'double precision';
140 }
141
142 my ($precision, $scale, $column_type) = eval { $dbh->selectrow_array(<<'EOF', {}, lc $table, lc $col) };
143SELECT numeric_precision, numeric_scale, column_type
144FROM information_schema.columns
145WHERE lower(table_name) = ? AND lower(column_name) = ?
146EOF
147 $column_type = '' if not defined $column_type;
148
149 if ($info->{data_type} eq 'bit' && (not exists $info->{size})) {
150 $info->{size} = $precision if defined $precision;
151 }
152 elsif ($info->{data_type} =~ /^(?:float|double precision|decimal)\z/) {
153 if (defined $precision && defined $scale) {
154 if ($precision == 10 && $scale == 0) {
155 delete $info->{size};
156 }
157 else {
158 $info->{size} = [$precision,$scale];
159 }
160 }
161 }
162 elsif ($info->{data_type} eq 'year') {
163 if ($column_type =~ /\(2\)/) {
164 $info->{size} = 2;
165 }
166 elsif ($column_type =~ /\(4\)/ || $info->{size} == 4) {
167 delete $info->{size};
168 }
169 }
170 }
171
172 return $result;
173}
174
a8df0345 175sub _extra_column_info {
f430297e 176 no warnings 'uninitialized';
45be2ce7 177 my ($self, $table, $col, $info, $dbi_info) = @_;
a8df0345 178 my %extra_info;
78b7ccaa 179
45be2ce7 180 if ($dbi_info->{mysql_is_auto_increment}) {
a8df0345 181 $extra_info{is_auto_increment} = 1
182 }
45be2ce7 183 if ($dbi_info->{mysql_type_name} =~ /\bunsigned\b/i) {
46bef65f 184 $extra_info{extra}{unsigned} = 1;
185 }
45be2ce7 186 if ($dbi_info->{mysql_values}) {
187 $extra_info{extra}{list} = $dbi_info->{mysql_values};
8fdd52a2 188 }
45be2ce7 189 if ( $dbi_info->{COLUMN_DEF} =~ /^CURRENT_TIMESTAMP\z/i
190 && $dbi_info->{mysql_type_name} =~ /^TIMESTAMP\z/i) {
3facc532 191
f430297e 192 $extra_info{default_value} = \'CURRENT_TIMESTAMP';
193 }
8fdd52a2 194
a8df0345 195 return \%extra_info;
8fdd52a2 196}
197
996be9ee 198=head1 SEE ALSO
199
200L<DBIx::Class::Schema::Loader>, L<DBIx::Class::Schema::Loader::Base>,
201L<DBIx::Class::Schema::Loader::DBI>
202
be80bba7 203=head1 AUTHOR
204
9cc8e7e1 205See L<DBIx::Class::Schema::Loader/AUTHOR> and L<DBIx::Class::Schema::Loader/CONTRIBUTORS>.
be80bba7 206
207=head1 LICENSE
208
209This library is free software; you can redistribute it and/or modify it under
210the same terms as Perl itself.
211
996be9ee 212=cut
213
2141;
26334ec1 215# vim:et sw=4 sts=4 tw=0: