workaround to get auto_increment working from PG "serial" datatype. i didn't do...
[dbsrgits/SQL-Translator.git] / lib / SQL / Translator / Producer / MySQL.pm
CommitLineData
9398955f 1package SQL::Translator::Producer::MySQL;
2
49e1eb70 3# -------------------------------------------------------------------
0a7fc605 4# $Id: MySQL.pm,v 1.14 2003-04-17 19:42:33 allenday 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 ];
0a7fc605 27$VERSION = sprintf "%d.%02d", q$Revision: 1.14 $ =~ /(\d+)\.(\d+)/;
5636ed00 28$DEBUG = 0 unless defined $DEBUG;
9398955f 29
30use Data::Dumper;
1a24938d 31use SQL::Translator::Utils qw(debug);
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;
60 unless ( $no_comments ) {
61 $create .= sprintf "--\n-- Created by %s\n-- Created on %s\n--\n\n",
62 __PACKAGE__, scalar localtime;
63 }
9398955f 64
758ab1cd 65 for my $table ( keys %{ $data } ) {
1a24938d 66 debug("PKG: Looking at table '$table'\n");
9398955f 67 my $table_data = $data->{$table};
d529894e 68 my @fields = sort {
69 $table_data->{'fields'}->{$a}->{'order'}
70 <=>
71 $table_data->{'fields'}->{$b}->{'order'}
72 } keys %{$table_data->{'fields'}};
9398955f 73
d529894e 74 #
9398955f 75 # Header. Should this look like what mysqldump produces?
d529894e 76 #
77 $create .= "--\n-- Table: $table\n--\n" unless $no_comments;
2620fc1c 78 $create .= qq[DROP TABLE IF EXISTS $table;\n] if $add_drop_table;
c45c546e 79 $create .= "CREATE TABLE $table (";
9398955f 80
d529894e 81 #
9398955f 82 # Fields
d529894e 83 #
9398955f 84 for (my $i = 0; $i <= $#fields; $i++) {
85 my $field = $fields[$i];
1a24938d 86 debug("PKG: Looking at field '$field'\n");
9398955f 87 my $field_data = $table_data->{'fields'}->{$field};
88 my @fdata = ("", $field);
c45c546e 89 $create .= "\n";
9398955f 90
91 # data type and size
2620fc1c 92 my $attr = uc $field_data->{'data_type'} eq 'SET'
93 ? 'list' : 'size';
94 my @values = @{ $field_data->{ $attr } || [] };
95 my $data_type = $field_data->{'data_type'};
96
97 if ( $data_type eq 'number' ) {
98 # not an integer
99 if ( scalar @values > 1 ) {
100 $data_type = 'double';
101 }
102 elsif ( $values[0] >= 12 ) {
103 $data_type = 'bigint';
104 }
105 elsif ( $values[0] <= 1 ) {
106 $data_type = 'tinyint';
107 }
108 else {
109 $data_type = 'int';
110 }
111 }
112 elsif ( exists $translate{ $data_type } ) {
113 $data_type = $translate{ $data_type };
114 }
115
0a7fc605 116 push @fdata, sprintf "%s%s",
2620fc1c 117 $data_type,
0a7fc605 118 defined( $values[0] )
2620fc1c 119 ? '(' . join( ', ', @values ) . ')'
d529894e 120 : '';
121
122 # MySQL qualifiers
123 for my $qual ( qw[ binary unsigned zerofill ] ) {
124 push @fdata, $qual
125 if $field_data->{ $qual } ||
126 $field_data->{ uc $qual };
127 }
9398955f 128
129 # Null?
130 push @fdata, "NOT NULL" unless $field_data->{'null'};
131
132 # Default? XXX Need better quoting!
d529894e 133 my $default = $field_data->{'default'};
134 if ( defined $default ) {
135 if ( uc $default eq 'NULL') {
136 push @fdata, "DEFAULT NULL";
9398955f 137 } else {
138 push @fdata, "DEFAULT '$default'";
139 }
140 }
141
142 # auto_increment?
143 push @fdata, "auto_increment" if $field_data->{'is_auto_inc'};
144
145 # primary key?
d529894e 146 # This is taken care of in the indices, could be duplicated here
147 # push @fdata, "PRIMARY KEY" if $field_data->{'is_primary_key'};
9398955f 148
149
d529894e 150 $create .= (join " ", '', @fdata);
9398955f 151 $create .= "," unless ($i == $#fields);
9398955f 152 }
153
d529894e 154 #
155 # Indices
156 #
157 my @index_creates;
2620fc1c 158 my @indices = @{ $table_data->{'indices'} || [] };
159 my @constraints = @{ $table_data->{'constraints'} || [] };
160 for my $key ( @indices, @constraints ) {
d529894e 161 my ($name, $type, $fields) = @{ $key }{ qw[ name type fields ] };
162 $name ||= '';
163 my $index_type =
164 $type eq 'primary_key' ? 'PRIMARY KEY' :
2620fc1c 165 $type eq 'unique' ? 'UNIQUE KEY' :
166 $type eq 'key' ? 'KEY' : '';
167 next unless $index_type;
d529894e 168 push @index_creates,
169 " $index_type $name (" . join( ', ', @$fields ) . ')';
c45c546e 170 }
9398955f 171
d529894e 172 if ( @index_creates ) {
173 $create .= join(",\n", '', @index_creates);
174 }
175
176 #
5e56da9a 177 # Constraints -- need to handle more than just FK. -ky
178 #
2620fc1c 179 my @constraint_defs;
180 for my $constraint ( @constraints ) {
5e56da9a 181 my $name = $constraint->{'name'} || '';
182 my $type = $constraint->{'type'};
183 my $fields = $constraint->{'fields'};
184 my $ref_table = $constraint->{'reference_table'};
185 my $ref_fields = $constraint->{'reference_fields'};
186 my $match_type = $constraint->{'match_type'} || '';
187 my $on_delete = $constraint->{'on_delete_do'};
188 my $on_update = $constraint->{'on_update_do'};
189
190 if ( $type eq 'foreign_key' ) {
191 my $def = join(' ', map { $_ || () } ' FOREIGN KEY', $name );
192 if ( @$fields ) {
193 $def .= ' (' . join( ', ', @$fields ) . ')';
194 }
195 $def .= " REFERENCES $ref_table";
196
023c4026 197 if ( @{ $ref_fields || [] } ) {
5e56da9a 198 $def .= ' (' . join( ', ', @$ref_fields ) . ')';
199 }
200
201 if ( $match_type ) {
202 $def .= ' MATCH ' .
203 ( $match_type =~ /full/i ) ? 'FULL' : 'PARTIAL';
204 }
205
586809da 206 if ( @{ $on_delete || [] } ) {
207 $def .= ' ON DELETE '.join(' ', @$on_delete);
208 }
209
210 if ( @{ $on_update || [] } ) {
211 $def .= ' ON UPDATE '.join(' ', @$on_update);
212 }
5e56da9a 213
2620fc1c 214 push @constraint_defs, $def;
5e56da9a 215 }
216 }
217
2620fc1c 218 $create .= join(",\n", '', @constraint_defs) if @constraint_defs;
5e56da9a 219
220 #
9398955f 221 # Footer
d529894e 222 #
c45c546e 223 $create .= "\n)";
ab0aa010 224 while ( my ( $key, $val ) = each %{ $table_data->{'table_options'} ||= { } } ) {
d529894e 225 $create .= " $key=$val"
226 }
9398955f 227 $create .= ";\n\n";
228 }
229
9398955f 230 return $create;
231}
232
9398955f 2331;
234__END__
235
236=head1 NAME
237
758ab1cd 238SQL::Translator::Producer::MySQL - MySQL-specific producer for SQL::Translator
9398955f 239
9398955f 240=head1 AUTHOR
241
758ab1cd 242darren chamberlain E<lt>darren@cpan.orgE<gt>,
243Ken Y. Clark E<lt>kclark@cpan.orgE<gt>