Muffled a warning message, by changing '">...
[dbsrgits/SQL-Translator.git] / lib / SQL / Translator / Parser / MySQL.pm
CommitLineData
16dc9970 1package SQL::Translator::Parser::MySQL;
2
49e1eb70 3# -------------------------------------------------------------------
13aec984 4# $Id: MySQL.pm,v 1.45 2004-11-25 22:32:48 grommit Exp $
49e1eb70 5# -------------------------------------------------------------------
90075866 6# Copyright (C) 2002-4 SQLFairy Authors
077ebf34 7#
8# This program is free software; you can redistribute it and/or
9# modify it under the terms of the GNU General Public License as
10# published by the Free Software Foundation; version 2.
11#
12# This program is distributed in the hope that it will be useful, but
13# WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15# General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License
18# along with this program; if not, write to the Free Software
19# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
20# 02111-1307 USA
21# -------------------------------------------------------------------
16dc9970 22
d529894e 23=head1 NAME
24
25SQL::Translator::Parser::MySQL - parser for MySQL
26
27=head1 SYNOPSIS
28
29 use SQL::Translator;
30 use SQL::Translator::Parser::MySQL;
31
32 my $translator = SQL::Translator->new;
33 $translator->parser("SQL::Translator::Parser::MySQL");
34
35=head1 DESCRIPTION
36
37The grammar is influenced heavily by Tim Bunce's "mysql2ora" grammar.
38
629b76f9 39Here's the word from the MySQL site
40(http://www.mysql.com/doc/en/CREATE_TABLE.html):
41
42 CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name [(create_definition,...)]
43 [table_options] [select_statement]
44
45 or
46
47 CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name LIKE old_table_name;
48
49 create_definition:
50 col_name type [NOT NULL | NULL] [DEFAULT default_value] [AUTO_INCREMENT]
51 [PRIMARY KEY] [reference_definition]
52 or PRIMARY KEY (index_col_name,...)
53 or KEY [index_name] (index_col_name,...)
54 or INDEX [index_name] (index_col_name,...)
55 or UNIQUE [INDEX] [index_name] (index_col_name,...)
56 or FULLTEXT [INDEX] [index_name] (index_col_name,...)
57 or [CONSTRAINT symbol] FOREIGN KEY [index_name] (index_col_name,...)
58 [reference_definition]
59 or CHECK (expr)
60
61 type:
62 TINYINT[(length)] [UNSIGNED] [ZEROFILL]
63 or SMALLINT[(length)] [UNSIGNED] [ZEROFILL]
64 or MEDIUMINT[(length)] [UNSIGNED] [ZEROFILL]
65 or INT[(length)] [UNSIGNED] [ZEROFILL]
66 or INTEGER[(length)] [UNSIGNED] [ZEROFILL]
67 or BIGINT[(length)] [UNSIGNED] [ZEROFILL]
68 or REAL[(length,decimals)] [UNSIGNED] [ZEROFILL]
69 or DOUBLE[(length,decimals)] [UNSIGNED] [ZEROFILL]
70 or FLOAT[(length,decimals)] [UNSIGNED] [ZEROFILL]
71 or DECIMAL(length,decimals) [UNSIGNED] [ZEROFILL]
72 or NUMERIC(length,decimals) [UNSIGNED] [ZEROFILL]
73 or CHAR(length) [BINARY]
74 or VARCHAR(length) [BINARY]
75 or DATE
76 or TIME
77 or TIMESTAMP
78 or DATETIME
79 or TINYBLOB
80 or BLOB
81 or MEDIUMBLOB
82 or LONGBLOB
83 or TINYTEXT
84 or TEXT
85 or MEDIUMTEXT
86 or LONGTEXT
87 or ENUM(value1,value2,value3,...)
88 or SET(value1,value2,value3,...)
89
90 index_col_name:
91 col_name [(length)]
92
93 reference_definition:
94 REFERENCES tbl_name [(index_col_name,...)]
95 [MATCH FULL | MATCH PARTIAL]
96 [ON DELETE reference_option]
97 [ON UPDATE reference_option]
98
99 reference_option:
100 RESTRICT | CASCADE | SET NULL | NO ACTION | SET DEFAULT
101
102 table_options:
103 TYPE = {BDB | HEAP | ISAM | InnoDB | MERGE | MRG_MYISAM | MYISAM }
104 or AUTO_INCREMENT = #
105 or AVG_ROW_LENGTH = #
106 or CHECKSUM = {0 | 1}
107 or COMMENT = "string"
108 or MAX_ROWS = #
109 or MIN_ROWS = #
110 or PACK_KEYS = {0 | 1 | DEFAULT}
111 or PASSWORD = "string"
112 or DELAY_KEY_WRITE = {0 | 1}
113 or ROW_FORMAT= { default | dynamic | fixed | compressed }
114 or RAID_TYPE= {1 | STRIPED | RAID0 } RAID_CHUNKS=# RAID_CHUNKSIZE=#
115 or UNION = (table_name,[table_name...])
116 or INSERT_METHOD= {NO | FIRST | LAST }
117 or DATA DIRECTORY="absolute path to directory"
118 or INDEX DIRECTORY="absolute path to directory"
119
13aec984 120A subset of the ALTER TABLE syntax that allows addition of foreign keys:
121
122 ALTER [IGNORE] TABLE tbl_name alter_specification [, alter_specification] ...
123
124 alter_specification:
125 ADD [CONSTRAINT [symbol]]
126 FOREIGN KEY [index_name] (index_col_name,...)
127 [reference_definition]
128
129A subset of INSERT that we ignore:
130
131 INSERT anything
132
d529894e 133=cut
134
16dc9970 135use strict;
d529894e 136use vars qw[ $DEBUG $VERSION $GRAMMAR @EXPORT_OK ];
13aec984 137$VERSION = sprintf "%d.%02d", q$Revision: 1.45 $ =~ /(\d+)\.(\d+)/;
8d0f3086 138$DEBUG = 0 unless defined $DEBUG;
077ebf34 139
d529894e 140use Data::Dumper;
077ebf34 141use Parse::RecDescent;
142use Exporter;
143use base qw(Exporter);
144
145@EXPORT_OK = qw(parse);
146
d529894e 147# Enable warnings within the Parse::RecDescent module.
148$::RD_ERRORS = 1; # Make sure the parser dies when it encounters an error
149$::RD_WARN = 1; # Enable warnings. This will warn on unused rules &c.
150$::RD_HINT = 1; # Give out hints to help fix problems.
151
d529894e 152$GRAMMAR = q!
153
8ccdeb42 154{
13aec984 155 my ( $database_name, %tables, $table_order, @table_comments );
8ccdeb42 156}
d529894e 157
629b76f9 158#
159# The "eofile" rule makes the parser fail if any "statement" rule
160# fails. Otherwise, the first successful match by a "statement"
161# won't cause the failure needed to know that the parse, as a whole,
162# failed. -ky
163#
13aec984 164startrule : statement(s) eofile {
165 { tables => \%tables, database_name => $database_name }
166}
629b76f9 167
168eofile : /^\Z/
d529894e 169
170statement : comment
dcb4fa06 171 | use
33d0d6d4 172 | set
61745327 173 | drop
d529894e 174 | create
13aec984 175 | alter
176 | insert
d529894e 177 | <error>
178
dcb4fa06 179use : /use/i WORD ';'
13aec984 180 {
181 $database_name = $item[2];
182 @table_comments = ();
183 }
dcb4fa06 184
33d0d6d4 185set : /set/i /[^;]+/ ';'
c5dabd71 186 { @table_comments = () }
734dfc91 187
2e8dfb76 188drop : /drop/i TABLE /[^;]+/ ';'
33d0d6d4 189
61745327 190drop : /drop/i WORD(s) ';'
c5dabd71 191 { @table_comments = () }
61745327 192
13aec984 193insert : /insert/i /[^;]+/ ';'
194
195alter : ALTER TABLE table_name alter_specification(s /,/) ';'
196 {
197 my $table_name = $item{'table_name'};
198 die "Cannot ALTER table '$table_name'; it does not exist"
199 unless $tables{ $table_name };
200 for my $definition ( @{ $item[4] } ) {
201 $definition->{'extra'}->{'alter'} = 1;
202 push @{ $tables{ $table_name }{'constraints'} }, $definition;
203 }
204 }
205
206alter_specification : ADD foreign_key_def
207 { $return = $item[2] }
208
dcb4fa06 209create : CREATE /database/i WORD ';'
c5dabd71 210 { @table_comments = () }
dcb4fa06 211
13aec984 212create : CREATE TEMPORARY(?) TABLE opt_if_not_exists(?) table_name '(' create_definition(s /,/) /(,\s*)?\)/ table_option(s?) ';'
d529894e 213 {
214 my $table_name = $item{'table_name'};
215 $tables{ $table_name }{'order'} = ++$table_order;
216 $tables{ $table_name }{'table_name'} = $table_name;
217
734dfc91 218 if ( @table_comments ) {
219 $tables{ $table_name }{'comments'} = [ @table_comments ];
220 @table_comments = ();
221 }
222
61745327 223 my $i = 1;
40c1ade1 224 for my $definition ( @{ $item[7] } ) {
f2cf1734 225 if ( $definition->{'supertype'} eq 'field' ) {
d529894e 226 my $field_name = $definition->{'name'};
227 $tables{ $table_name }{'fields'}{ $field_name } =
228 { %$definition, order => $i };
229 $i++;
230
231 if ( $definition->{'is_primary_key'} ) {
f2cf1734 232 push @{ $tables{ $table_name }{'constraints'} },
d529894e 233 {
234 type => 'primary_key',
235 fields => [ $field_name ],
16dc9970 236 }
d529894e 237 ;
238 }
dd2ef5ae 239 }
f2cf1734 240 elsif ( $definition->{'supertype'} eq 'constraint' ) {
f2cf1734 241 push @{ $tables{ $table_name }{'constraints'} }, $definition;
40c1ade1 242 }
f2cf1734 243 elsif ( $definition->{'supertype'} eq 'index' ) {
734dfc91 244 push @{ $tables{ $table_name }{'indices'} }, $definition;
dd2ef5ae 245 }
d529894e 246 }
dd2ef5ae 247
02a21f1a 248 if ( my @options = @{ $item{'table_option(s?)'} } ) {
249 $tables{ $table_name }{'table_options'} = \@options;
d529894e 250 }
58a88238 251
252 1;
d529894e 253 }
dd2ef5ae 254
40c1ade1 255opt_if_not_exists : /if not exists/i
256
f2cf1734 257create : CREATE UNIQUE(?) /(index|key)/i index_name /on/i table_name '(' field_name(s /,/) ')' ';'
d529894e 258 {
734dfc91 259 @table_comments = ();
d529894e 260 push @{ $tables{ $item{'table_name'} }{'indices'} },
261 {
262 name => $item[4],
263 type => $item[2] ? 'unique' : 'normal',
264 fields => $item[8],
dd2ef5ae 265 }
d529894e 266 ;
267 }
dd2ef5ae 268
f2cf1734 269create_definition : constraint
270 | index
d529894e 271 | field
02a21f1a 272 | comment
d529894e 273 | <error>
274
734dfc91 275comment : /^\s*(?:#|-{2}).*\n/
276 {
277 my $comment = $item[1];
a82fa2cb 278 $comment =~ s/^\s*(#|--)\s*//;
734dfc91 279 $comment =~ s/\s*$//;
280 $return = $comment;
281 push @table_comments, $comment;
282 }
283
284field_comment : /^\s*(?:#|-{2}).*\n/
285 {
286 my $comment = $item[1];
a82fa2cb 287 $comment =~ s/^\s*(#|--)\s*//;
734dfc91 288 $comment =~ s/\s*$//;
289 $return = $comment;
290 }
d529894e 291
292blank : /\s*/
293
734dfc91 294field : field_comment(s?) field_name data_type field_qualifier(s?) reference_definition(?) field_comment(s?)
d529894e 295 {
734dfc91 296 my %qualifiers = map { %$_ } @{ $item{'field_qualifier(s?)'} || [] };
d529894e 297 if ( my @type_quals = @{ $item{'data_type'}{'qualifiers'} || [] } ) {
298 $qualifiers{ $_ } = 1 for @type_quals;
299 }
300
c5dabd71 301 my $null = defined $qualifiers{'not_null'}
302 ? $qualifiers{'not_null'} : 1;
303 delete $qualifiers{'not_null'};
304
88b89793 305 my @comments = ( @{ $item[1] }, @{ $item[6] } );
306
d529894e 307 $return = {
f2cf1734 308 supertype => 'field',
309 name => $item{'field_name'},
310 data_type => $item{'data_type'}{'type'},
311 size => $item{'data_type'}{'size'},
312 list => $item{'data_type'}{'list'},
313 null => $null,
314 constraints => $item{'reference_definition(?)'},
88b89793 315 comments => [ @comments ],
d529894e 316 %qualifiers,
317 }
318 }
319 | <error>
dd2ef5ae 320
d529894e 321field_qualifier : not_null
322 {
323 $return = {
324 null => $item{'not_null'},
325 }
326 }
16dc9970 327
d529894e 328field_qualifier : default_val
329 {
330 $return = {
331 default => $item{'default_val'},
332 }
333 }
16dc9970 334
d529894e 335field_qualifier : auto_inc
336 {
337 $return = {
338 is_auto_inc => $item{'auto_inc'},
339 }
340 }
16dc9970 341
d529894e 342field_qualifier : primary_key
343 {
344 $return = {
345 is_primary_key => $item{'primary_key'},
346 }
347 }
16dc9970 348
d529894e 349field_qualifier : unsigned
350 {
351 $return = {
352 is_unsigned => $item{'unsigned'},
353 }
354 }
16dc9970 355
095b4549 356field_qualifier : /character set/i WORD
357 {
358 $return = {
359 character_set => $item[2],
360 }
361 }
362
658637cd 363reference_definition : /references/i table_name parens_field_list(?) match_type(?) on_delete_do(?) on_update_do(?)
364 {
40c1ade1 365 $return = {
658637cd 366 type => 'foreign_key',
367 reference_table => $item[2],
368 reference_fields => $item[3][0],
369 match_type => $item[4][0],
370 on_delete_do => $item[5][0],
371 on_update_do => $item[6][0],
372 }
373 }
374
02a21f1a 375match_type : /match full/i { 'full' }
658637cd 376 |
02a21f1a 377 /match partial/i { 'partial' }
658637cd 378
379on_delete_do : /on delete/i reference_option
380 { $item[2] }
381
382on_update_do : /on update/i reference_option
383 { $item[2] }
384
385reference_option: /restrict/i |
386 /cascade/i |
387 /set null/i |
388 /no action/i |
389 /set default/i
390 { $item[1] }
391
f2cf1734 392index : normal_index
371f5f88 393 | fulltext_index
58a88238 394 | <error>
d529894e 395
0d41bc9b 396table_name : NAME
d529894e 397
0d41bc9b 398field_name : NAME
d529894e 399
02a21f1a 400index_name : NAME
d529894e 401
402data_type : WORD parens_value_list(s?) type_qualifier(s?)
403 {
404 my $type = $item[1];
405 my $size; # field size, applicable only to non-set fields
406 my $list; # set list, applicable only to sets (duh)
407
44fcd0b5 408 if ( uc($type) =~ /^(SET|ENUM)$/ ) {
d529894e 409 $size = undef;
410 $list = $item[2][0];
411 }
412 else {
413 $size = $item[2][0];
414 $list = [];
415 }
416
6333c482 417 unless ( @{ $size || [] } ) {
418 if ( lc $type eq 'tinyint' ) {
7898fb70 419 $size = 4;
6333c482 420 }
421 elsif ( lc $type eq 'smallint' ) {
7898fb70 422 $size = 6;
6333c482 423 }
424 elsif ( lc $type eq 'mediumint' ) {
7898fb70 425 $size = 9;
6333c482 426 }
c736c39c 427 elsif ( $type =~ /^int(eger)?$/ ) {
f2cf1734 428 $type = 'int';
7898fb70 429 $size = 11;
6333c482 430 }
431 elsif ( lc $type eq 'bigint' ) {
7898fb70 432 $size = 20;
6333c482 433 }
1eb08c80 434 elsif (
435 lc $type =~ /(float|double|decimal|numeric|real|fixed|dec)/
436 ) {
6333c482 437 $size = [8,2];
438 }
439 }
440
7898fb70 441 if ( $type =~ /^tiny(text|blob)$/i ) {
442 $size = 255;
256d534a 443 }
7898fb70 444 elsif ( $type =~ /^(blob|text)$/i ) {
445 $size = 65_535;
256d534a 446 }
7898fb70 447 elsif ( $type =~ /^medium(blob|text)$/i ) {
448 $size = 16_777_215;
256d534a 449 }
7898fb70 450 elsif ( $type =~ /^long(blob|text)$/i ) {
451 $size = 4_294_967_295;
256d534a 452 }
453
d529894e 454 $return = {
455 type => $type,
456 size => $size,
457 list => $list,
458 qualifiers => $item[3],
459 }
460 }
16dc9970 461
658637cd 462parens_field_list : '(' field_name(s /,/) ')'
463 { $item[2] }
464
d529894e 465parens_value_list : '(' VALUE(s /,/) ')'
466 { $item[2] }
16dc9970 467
d529894e 468type_qualifier : /(BINARY|UNSIGNED|ZEROFILL)/i
469 { lc $item[1] }
16dc9970 470
d529894e 471field_type : WORD
16dc9970 472
d529894e 473create_index : /create/i /index/i
dd2ef5ae 474
d529894e 475not_null : /not/i /null/i { $return = 0 }
16dc9970 476
d529894e 477unsigned : /unsigned/i { $return = 0 }
16dc9970 478
09fa21a6 479#default_val : /default/i /(?:')?[\s\w\d:.-]*(?:')?/
480# {
481# $item[2] =~ s/'//g;
482# $return = $item[2];
483# }
484
485default_val : /default/i /'(?:.*?\\')*.*?'|(?:')?[\w\d:.-]*(?:')?/
486 {
487 $item[2] =~ s/^\s*'|'\s*$//g;
d529894e 488 $return = $item[2];
489 }
16dc9970 490
d529894e 491auto_inc : /auto_increment/i { 1 }
16dc9970 492
d529894e 493primary_key : /primary/i /key/i { 1 }
16dc9970 494
f2cf1734 495constraint : primary_key_def
496 | unique_key_def
497 | foreign_key_def
498 | <error>
499
02a21f1a 500foreign_key_def : foreign_key_def_begin parens_field_list reference_definition
40c1ade1 501 {
502 $return = {
f2cf1734 503 supertype => 'constraint',
40c1ade1 504 type => 'foreign_key',
02a21f1a 505 name => $item[1],
09fa21a6 506 fields => $item[2],
40c1ade1 507 %{ $item{'reference_definition'} },
508 }
509 }
510
02a21f1a 511foreign_key_def_begin : /constraint/i /foreign key/i
512 { $return = '' }
513 |
514 /constraint/i WORD /foreign key/i
515 { $return = $item[2] }
516 |
517 /foreign key/i
518 { $return = '' }
40c1ade1 519
1853ba82 520primary_key_def : primary_key index_name(?) '(' name_with_opt_paren(s /,/) ')'
d529894e 521 {
f2cf1734 522 $return = {
523 supertype => 'constraint',
524 name => $item{'index_name(?)'}[0],
525 type => 'primary_key',
526 fields => $item[4],
58a88238 527 };
d529894e 528 }
16dc9970 529
f2cf1734 530unique_key_def : UNIQUE KEY(?) index_name(?) '(' name_with_opt_paren(s /,/) ')'
d529894e 531 {
f2cf1734 532 $return = {
533 supertype => 'constraint',
534 name => $item{'index_name(?)'}[0],
535 type => 'unique',
536 fields => $item[5],
d529894e 537 }
538 }
16dc9970 539
f2cf1734 540normal_index : KEY index_name(?) '(' name_with_opt_paren(s /,/) ')'
d529894e 541 {
f2cf1734 542 $return = {
543 supertype => 'index',
544 type => 'normal',
545 name => $item{'index_name(?)'}[0],
546 fields => $item[4],
d529894e 547 }
548 }
16dc9970 549
f2cf1734 550fulltext_index : /fulltext/i KEY(?) index_name(?) '(' name_with_opt_paren(s /,/) ')'
371f5f88 551 {
f2cf1734 552 $return = {
553 supertype => 'index',
554 type => 'fulltext',
555 name => $item{'index_name(?)'}[0],
556 fields => $item[5],
371f5f88 557 }
558 }
559
d529894e 560name_with_opt_paren : NAME parens_value_list(s?)
561 { $item[2][0] ? "$item[1]($item[2][0][0])" : $item[1] }
16dc9970 562
f2cf1734 563UNIQUE : /unique/i { 1 }
16dc9970 564
f2cf1734 565KEY : /key/i | /index/i
16dc9970 566
02a21f1a 567table_option : WORD /\s*=\s*/ WORD
d529894e 568 {
02a21f1a 569 $return = { $item[1] => $item[3] };
d529894e 570 }
16dc9970 571
13aec984 572ADD : /add/i
573
574ALTER : /alter/i
575
40c1ade1 576CREATE : /create/i
577
578TEMPORARY : /temporary/i
579
580TABLE : /table/i
581
d529894e 582WORD : /\w+/
16dc9970 583
d529894e 584DIGITS : /\d+/
16dc9970 585
d529894e 586COMMA : ','
16dc9970 587
d529894e 588NAME : "`" /\w+/ "`"
589 { $item[2] }
590 | /\w+/
591 { $item[1] }
16dc9970 592
d529894e 593VALUE : /[-+]?\.?\d+(?:[eE]\d+)?/
594 { $item[1] }
f2cf1734 595 | /'.*?'/
596 {
597 # remove leading/trailing quotes
598 my $val = $item[1];
599 $val =~ s/^['"]|['"]$//g;
600 $return = $val;
601 }
d529894e 602 | /NULL/
603 { 'NULL' }
16dc9970 604
d529894e 605!;
16dc9970 606
d529894e 607# -------------------------------------------------------------------
608sub parse {
70944bc5 609 my ( $translator, $data ) = @_;
40c1ade1 610 my $parser = Parse::RecDescent->new($GRAMMAR);
077ebf34 611
e099bee9 612 local $::RD_TRACE = $translator->trace ? 1 : undef;
613 local $DEBUG = $translator->debug;
d529894e 614
615 unless (defined $parser) {
616 return $translator->error("Error instantiating Parse::RecDescent ".
617 "instance: Bad grammer");
618 }
619
620 my $result = $parser->startrule($data);
40c1ade1 621 return $translator->error( "Parse failed." ) unless defined $result;
13aec984 622 warn "Parse result:".Dumper( $result ) if $DEBUG;
8ccdeb42 623
70944bc5 624 my $schema = $translator->schema;
13aec984 625 $schema->name($result->{'database_name'}) if $result->{'database_name'};
626
034ecdec 627 my @tables = sort {
13aec984 628 $result->{'tables'}{ $a }{'order'}
629 <=>
630 $result->{'tables'}{ $b }{'order'}
631 } keys %{ $result->{'tables'} };
034ecdec 632
633 for my $table_name ( @tables ) {
13aec984 634 my $tdata = $result->{tables}{ $table_name };
8ccdeb42 635 my $table = $schema->add_table(
636 name => $tdata->{'table_name'},
40c1ade1 637 ) or die $schema->error;
8ccdeb42 638
734dfc91 639 $table->comments( $tdata->{'comments'} );
f2cf1734 640
8ccdeb42 641 my @fields = sort {
642 $tdata->{'fields'}->{$a}->{'order'}
643 <=>
644 $tdata->{'fields'}->{$b}->{'order'}
645 } keys %{ $tdata->{'fields'} };
646
647 for my $fname ( @fields ) {
648 my $fdata = $tdata->{'fields'}{ $fname };
649 my $field = $table->add_field(
650 name => $fdata->{'name'},
651 data_type => $fdata->{'data_type'},
652 size => $fdata->{'size'},
653 default_value => $fdata->{'default'},
654 is_auto_increment => $fdata->{'is_auto_inc'},
655 is_nullable => $fdata->{'null'},
88b89793 656 comments => $fdata->{'comments'},
40c1ade1 657 ) or die $table->error;
f2cf1734 658
659 $table->primary_key( $field->name ) if $fdata->{'is_primary_key'};
660
661 for my $qual ( qw[ binary unsigned zerofill list ] ) {
662 if ( my $val = $fdata->{ $qual } || $fdata->{ uc $qual } ) {
663 next if ref $val eq 'ARRAY' && !@$val;
664 $field->extra( $qual, $val );
665 }
666 }
667
668 if ( $field->data_type =~ /(set|enum)/i && !$field->size ) {
669 my %extra = $field->extra;
d14fe688 670 my $longest = 0;
f2cf1734 671 for my $len ( map { length } @{ $extra{'list'} || [] } ) {
672 $longest = $len if $len > $longest;
673 }
674 $field->size( $longest ) if $longest;
675 }
676
677 for my $cdata ( @{ $fdata->{'constraints'} } ) {
678 next unless $cdata->{'type'} eq 'foreign_key';
679 $cdata->{'fields'} ||= [ $field->name ];
680 push @{ $tdata->{'constraints'} }, $cdata;
681 }
682 }
683
684 for my $idata ( @{ $tdata->{'indices'} || [] } ) {
685 my $index = $table->add_index(
686 name => $idata->{'name'},
687 type => uc $idata->{'type'},
688 fields => $idata->{'fields'},
689 ) or die $table->error;
690 }
691
02a21f1a 692 if ( my @options = @{ $tdata->{'table_options'} || [] } ) {
693 $table->options( \@options ) or die $table->error;
694 }
695
f2cf1734 696 for my $cdata ( @{ $tdata->{'constraints'} || [] } ) {
697 my $constraint = $table->add_constraint(
698 name => $cdata->{'name'},
699 type => $cdata->{'type'},
700 fields => $cdata->{'fields'},
701 reference_table => $cdata->{'reference_table'},
702 reference_fields => $cdata->{'reference_fields'},
703 match_type => $cdata->{'match_type'} || '',
704 on_delete => $cdata->{'on_delete_do'},
705 on_update => $cdata->{'on_update_do'},
706 ) or die $table->error;
8ccdeb42 707 }
708 }
709
f62bd16c 710 return 1;
d529894e 711}
712
7131;
714
034ecdec 715# -------------------------------------------------------------------
d529894e 716# Where man is not nature is barren.
717# William Blake
034ecdec 718# -------------------------------------------------------------------
16dc9970 719
d529894e 720=pod
16dc9970 721
722=head1 AUTHOR
723
d529894e 724Ken Y. Clark E<lt>kclark@cpan.orgE<gt>,
8ccdeb42 725Chris Mungall E<lt>cjm@fruitfly.orgE<gt>.
16dc9970 726
727=head1 SEE ALSO
728
8ccdeb42 729perl(1), Parse::RecDescent, SQL::Translator::Schema.
16dc9970 730
731=cut