Cosmetic change in POD.
[dbsrgits/SQL-Translator.git] / lib / SQL / Translator / Producer / MySQL.pm
CommitLineData
9398955f 1package SQL::Translator::Producer::MySQL;
2
49e1eb70 3# -------------------------------------------------------------------
2d6979da 4# $Id: MySQL.pm,v 1.20 2003-05-12 14:59:15 kycl4rk Exp $
49e1eb70 5# -------------------------------------------------------------------
abfa405a 6# Copyright (C) 2003 Ken Y. Clark <kclark@cpan.org>,
7# darren chamberlain <darren@cpan.org>,
8# Chris Mungall <cjm@fruitfly.org>
9398955f 9#
10# This program is free software; you can redistribute it and/or
11# modify it under the terms of the GNU General Public License as
12# published by the Free Software Foundation; version 2.
13#
14# This program is distributed in the hope that it will be useful, but
15# WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17# General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License
20# along with this program; if not, write to the Free Software
21# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
22# 02111-1307 USA
23# -------------------------------------------------------------------
24
25use strict;
d529894e 26use vars qw[ $VERSION $DEBUG ];
2d6979da 27$VERSION = sprintf "%d.%02d", q$Revision: 1.20 $ =~ /(\d+)\.(\d+)/;
5636ed00 28$DEBUG = 0 unless defined $DEBUG;
9398955f 29
30use Data::Dumper;
5ee19df8 31use SQL::Translator::Utils qw(debug header_comment);
9398955f 32
2620fc1c 33my %translate = (
34 #
35 # Oracle types
36 #
37 varchar2 => 'varchar',
38 long => 'text',
39 CLOB => 'longtext',
40
41 #
42 # Sybase types
43 #
44 int => 'integer',
45 money => 'float',
46 real => 'double',
47 comment => 'text',
48 bit => 'tinyint',
49);
50
9398955f 51sub produce {
52 my ($translator, $data) = @_;
5636ed00 53 local $DEBUG = $translator->debug;
d529894e 54 my $no_comments = $translator->no_comments;
758ab1cd 55 my $add_drop_table = $translator->add_drop_table;
d529894e 56
1a24938d 57 debug("PKG: Beginning production\n");
d529894e 58
59 my $create;
5ee19df8 60 $create .= header_comment unless ($no_comments);
9398955f 61
758ab1cd 62 for my $table ( keys %{ $data } ) {
1a24938d 63 debug("PKG: Looking at table '$table'\n");
9398955f 64 my $table_data = $data->{$table};
d529894e 65 my @fields = sort {
66 $table_data->{'fields'}->{$a}->{'order'}
67 <=>
68 $table_data->{'fields'}->{$b}->{'order'}
69 } keys %{$table_data->{'fields'}};
9398955f 70
d529894e 71 #
9398955f 72 # Header. Should this look like what mysqldump produces?
d529894e 73 #
74 $create .= "--\n-- Table: $table\n--\n" unless $no_comments;
2620fc1c 75 $create .= qq[DROP TABLE IF EXISTS $table;\n] if $add_drop_table;
c45c546e 76 $create .= "CREATE TABLE $table (";
9398955f 77
d529894e 78 #
9398955f 79 # Fields
d529894e 80 #
9398955f 81 for (my $i = 0; $i <= $#fields; $i++) {
82 my $field = $fields[$i];
1a24938d 83 debug("PKG: Looking at field '$field'\n");
9398955f 84 my $field_data = $table_data->{'fields'}->{$field};
85 my @fdata = ("", $field);
c45c546e 86 $create .= "\n";
9398955f 87
88 # data type and size
2620fc1c 89 my $attr = uc $field_data->{'data_type'} eq 'SET'
90 ? 'list' : 'size';
91 my @values = @{ $field_data->{ $attr } || [] };
92 my $data_type = $field_data->{'data_type'};
93
94 if ( $data_type eq 'number' ) {
95 # not an integer
96 if ( scalar @values > 1 ) {
97 $data_type = 'double';
98 }
99 elsif ( $values[0] >= 12 ) {
100 $data_type = 'bigint';
101 }
102 elsif ( $values[0] <= 1 ) {
103 $data_type = 'tinyint';
104 }
105 else {
106 $data_type = 'int';
107 }
108 }
109 elsif ( exists $translate{ $data_type } ) {
110 $data_type = $translate{ $data_type };
111 }
112
0a7fc605 113 push @fdata, sprintf "%s%s",
2620fc1c 114 $data_type,
0a7fc605 115 defined( $values[0] )
2620fc1c 116 ? '(' . join( ', ', @values ) . ')'
d529894e 117 : '';
118
119 # MySQL qualifiers
120 for my $qual ( qw[ binary unsigned zerofill ] ) {
121 push @fdata, $qual
122 if $field_data->{ $qual } ||
123 $field_data->{ uc $qual };
124 }
9398955f 125
126 # Null?
127 push @fdata, "NOT NULL" unless $field_data->{'null'};
128
129 # Default? XXX Need better quoting!
d529894e 130 my $default = $field_data->{'default'};
131 if ( defined $default ) {
132 if ( uc $default eq 'NULL') {
133 push @fdata, "DEFAULT NULL";
9398955f 134 } else {
135 push @fdata, "DEFAULT '$default'";
136 }
137 }
138
139 # auto_increment?
140 push @fdata, "auto_increment" if $field_data->{'is_auto_inc'};
141
142 # primary key?
d529894e 143 # This is taken care of in the indices, could be duplicated here
144 # push @fdata, "PRIMARY KEY" if $field_data->{'is_primary_key'};
9398955f 145
146
d529894e 147 $create .= (join " ", '', @fdata);
9398955f 148 $create .= "," unless ($i == $#fields);
56120730 149 }
9398955f 150
d529894e 151 #
152 # Indices
153 #
154 my @index_creates;
2620fc1c 155 my @indices = @{ $table_data->{'indices'} || [] };
156 my @constraints = @{ $table_data->{'constraints'} || [] };
56120730 157
2620fc1c 158 for my $key ( @indices, @constraints ) {
d529894e 159 my ($name, $type, $fields) = @{ $key }{ qw[ name type fields ] };
160 $name ||= '';
3c32785b 161 $type ||= '';
d529894e 162 my $index_type =
163 $type eq 'primary_key' ? 'PRIMARY KEY' :
2620fc1c 164 $type eq 'unique' ? 'UNIQUE KEY' :
56120730 165 $type eq 'key' ? 'KEY' :
166 $type eq 'normal' ? 'KEY' : '';
167
2620fc1c 168 next unless $index_type;
56120730 169 push @index_creates,
d529894e 170 " $index_type $name (" . join( ', ', @$fields ) . ')';
c45c546e 171 }
9398955f 172
d529894e 173 if ( @index_creates ) {
174 $create .= join(",\n", '', @index_creates);
175 }
176
177 #
5e56da9a 178 # Constraints -- need to handle more than just FK. -ky
179 #
2620fc1c 180 my @constraint_defs;
181 for my $constraint ( @constraints ) {
5e56da9a 182 my $name = $constraint->{'name'} || '';
183 my $type = $constraint->{'type'};
184 my $fields = $constraint->{'fields'};
185 my $ref_table = $constraint->{'reference_table'};
186 my $ref_fields = $constraint->{'reference_fields'};
187 my $match_type = $constraint->{'match_type'} || '';
188 my $on_delete = $constraint->{'on_delete_do'};
189 my $on_update = $constraint->{'on_update_do'};
190
191 if ( $type eq 'foreign_key' ) {
192 my $def = join(' ', map { $_ || () } ' FOREIGN KEY', $name );
193 if ( @$fields ) {
194 $def .= ' (' . join( ', ', @$fields ) . ')';
195 }
196 $def .= " REFERENCES $ref_table";
197
023c4026 198 if ( @{ $ref_fields || [] } ) {
5e56da9a 199 $def .= ' (' . join( ', ', @$ref_fields ) . ')';
200 }
201
202 if ( $match_type ) {
203 $def .= ' MATCH ' .
204 ( $match_type =~ /full/i ) ? 'FULL' : 'PARTIAL';
205 }
206
586809da 207 if ( @{ $on_delete || [] } ) {
208 $def .= ' ON DELETE '.join(' ', @$on_delete);
209 }
210
211 if ( @{ $on_update || [] } ) {
212 $def .= ' ON UPDATE '.join(' ', @$on_update);
213 }
5e56da9a 214
2620fc1c 215 push @constraint_defs, $def;
5e56da9a 216 }
217 }
218
2620fc1c 219 $create .= join(",\n", '', @constraint_defs) if @constraint_defs;
5e56da9a 220
221 #
9398955f 222 # Footer
d529894e 223 #
c45c546e 224 $create .= "\n)";
95f99bd3 225 while (
226 my ( $key, $val ) = each %{ $table_data->{'table_options'} ||= {} }
227 ) {
d529894e 228 $create .= " $key=$val"
229 }
9398955f 230 $create .= ";\n\n";
231 }
232
9398955f 233 return $create;
234}
235
9398955f 2361;
237__END__
238
239=head1 NAME
240
758ab1cd 241SQL::Translator::Producer::MySQL - MySQL-specific producer for SQL::Translator
9398955f 242
2d6979da 243=head1 AUTHORS
9398955f 244
758ab1cd 245darren chamberlain E<lt>darren@cpan.orgE<gt>,
246Ken Y. Clark E<lt>kclark@cpan.orgE<gt>