Added comments lines to test data forworking with new YAML Producer output
[dbsrgits/SQL-Translator.git] / lib / SQL / Translator / Parser / MySQL.pm
CommitLineData
16dc9970 1package SQL::Translator::Parser::MySQL;
2
49e1eb70 3# -------------------------------------------------------------------
35843e6b 4# $Id: MySQL.pm,v 1.48 2005-06-15 17:58:42 kycl4rk 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 ];
35843e6b 137$VERSION = sprintf "%d.%02d", q$Revision: 1.48 $ =~ /(\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?)'} } ) {
35843e6b 249 for my $option ( @options ) {
250 my ( $key, $value ) = each %$option;
251 if ( $key eq 'comment' ) {
252 push @{ $tables{ $table_name }{'comments'} }, $value;
253 }
254 else {
255 push @{ $tables{ $table_name }{'table_options'} }, $option;
256 }
257 }
d529894e 258 }
58a88238 259
260 1;
d529894e 261 }
dd2ef5ae 262
40c1ade1 263opt_if_not_exists : /if not exists/i
264
f2cf1734 265create : CREATE UNIQUE(?) /(index|key)/i index_name /on/i table_name '(' field_name(s /,/) ')' ';'
d529894e 266 {
734dfc91 267 @table_comments = ();
d529894e 268 push @{ $tables{ $item{'table_name'} }{'indices'} },
269 {
270 name => $item[4],
271 type => $item[2] ? 'unique' : 'normal',
272 fields => $item[8],
dd2ef5ae 273 }
d529894e 274 ;
275 }
dd2ef5ae 276
f2cf1734 277create_definition : constraint
278 | index
d529894e 279 | field
02a21f1a 280 | comment
d529894e 281 | <error>
282
734dfc91 283comment : /^\s*(?:#|-{2}).*\n/
284 {
285 my $comment = $item[1];
a82fa2cb 286 $comment =~ s/^\s*(#|--)\s*//;
734dfc91 287 $comment =~ s/\s*$//;
288 $return = $comment;
289 push @table_comments, $comment;
290 }
291
e78d62f2 292comment : /\/\*/ /[^\*]+/ /\*\// ';'
293 {
294 my $comment = $item[2];
295 $comment =~ s/^\s*|\s*$//g;
296 $return = $comment;
297 }
298
734dfc91 299field_comment : /^\s*(?:#|-{2}).*\n/
300 {
301 my $comment = $item[1];
a82fa2cb 302 $comment =~ s/^\s*(#|--)\s*//;
734dfc91 303 $comment =~ s/\s*$//;
304 $return = $comment;
305 }
d529894e 306
35843e6b 307
308field_comment2 : /comment/i /'.*?'/
309 {
310 my $comment = $item[2];
311 $comment =~ s/^'//;
312 $comment =~ s/'$//;
313 $return = $comment;
314 }
315
d529894e 316blank : /\s*/
317
35843e6b 318field : field_comment(s?) field_name data_type field_qualifier(s?) field_comment2(?) reference_definition(?) on_update_do(?) field_comment(s?)
d529894e 319 {
734dfc91 320 my %qualifiers = map { %$_ } @{ $item{'field_qualifier(s?)'} || [] };
d529894e 321 if ( my @type_quals = @{ $item{'data_type'}{'qualifiers'} || [] } ) {
322 $qualifiers{ $_ } = 1 for @type_quals;
323 }
324
c5dabd71 325 my $null = defined $qualifiers{'not_null'}
326 ? $qualifiers{'not_null'} : 1;
327 delete $qualifiers{'not_null'};
328
35843e6b 329 my @comments = ( @{ $item[1] }, @{ $item[5] }, @{ $item[8] } );
88b89793 330
d529894e 331 $return = {
f2cf1734 332 supertype => 'field',
333 name => $item{'field_name'},
334 data_type => $item{'data_type'}{'type'},
335 size => $item{'data_type'}{'size'},
336 list => $item{'data_type'}{'list'},
337 null => $null,
338 constraints => $item{'reference_definition(?)'},
88b89793 339 comments => [ @comments ],
d529894e 340 %qualifiers,
341 }
342 }
343 | <error>
dd2ef5ae 344
d529894e 345field_qualifier : not_null
346 {
347 $return = {
348 null => $item{'not_null'},
349 }
350 }
16dc9970 351
d529894e 352field_qualifier : default_val
353 {
354 $return = {
355 default => $item{'default_val'},
356 }
357 }
16dc9970 358
d529894e 359field_qualifier : auto_inc
360 {
361 $return = {
362 is_auto_inc => $item{'auto_inc'},
363 }
364 }
16dc9970 365
d529894e 366field_qualifier : primary_key
367 {
368 $return = {
369 is_primary_key => $item{'primary_key'},
370 }
371 }
16dc9970 372
d529894e 373field_qualifier : unsigned
374 {
375 $return = {
376 is_unsigned => $item{'unsigned'},
377 }
378 }
16dc9970 379
095b4549 380field_qualifier : /character set/i WORD
381 {
382 $return = {
383 character_set => $item[2],
384 }
385 }
386
658637cd 387reference_definition : /references/i table_name parens_field_list(?) match_type(?) on_delete_do(?) on_update_do(?)
388 {
40c1ade1 389 $return = {
658637cd 390 type => 'foreign_key',
391 reference_table => $item[2],
392 reference_fields => $item[3][0],
393 match_type => $item[4][0],
394 on_delete_do => $item[5][0],
395 on_update_do => $item[6][0],
396 }
397 }
398
02a21f1a 399match_type : /match full/i { 'full' }
658637cd 400 |
02a21f1a 401 /match partial/i { 'partial' }
658637cd 402
403on_delete_do : /on delete/i reference_option
404 { $item[2] }
405
6fa97af6 406on_update_do :
407 /on update/i 'CURRENT_TIMESTAMP'
408 { $item[2] }
409 |
410 /on update/i reference_option
658637cd 411 { $item[2] }
412
413reference_option: /restrict/i |
414 /cascade/i |
415 /set null/i |
416 /no action/i |
417 /set default/i
418 { $item[1] }
419
f2cf1734 420index : normal_index
371f5f88 421 | fulltext_index
58a88238 422 | <error>
d529894e 423
0d41bc9b 424table_name : NAME
d529894e 425
0d41bc9b 426field_name : NAME
d529894e 427
02a21f1a 428index_name : NAME
d529894e 429
430data_type : WORD parens_value_list(s?) type_qualifier(s?)
431 {
432 my $type = $item[1];
433 my $size; # field size, applicable only to non-set fields
434 my $list; # set list, applicable only to sets (duh)
435
44fcd0b5 436 if ( uc($type) =~ /^(SET|ENUM)$/ ) {
d529894e 437 $size = undef;
438 $list = $item[2][0];
439 }
440 else {
441 $size = $item[2][0];
442 $list = [];
443 }
444
6333c482 445 unless ( @{ $size || [] } ) {
446 if ( lc $type eq 'tinyint' ) {
7898fb70 447 $size = 4;
6333c482 448 }
449 elsif ( lc $type eq 'smallint' ) {
7898fb70 450 $size = 6;
6333c482 451 }
452 elsif ( lc $type eq 'mediumint' ) {
7898fb70 453 $size = 9;
6333c482 454 }
e78d62f2 455 elsif ( $type =~ /^int(eger)?$/i ) {
f2cf1734 456 $type = 'int';
7898fb70 457 $size = 11;
6333c482 458 }
459 elsif ( lc $type eq 'bigint' ) {
7898fb70 460 $size = 20;
6333c482 461 }
1eb08c80 462 elsif (
463 lc $type =~ /(float|double|decimal|numeric|real|fixed|dec)/
464 ) {
6333c482 465 $size = [8,2];
466 }
467 }
468
7898fb70 469 if ( $type =~ /^tiny(text|blob)$/i ) {
470 $size = 255;
256d534a 471 }
7898fb70 472 elsif ( $type =~ /^(blob|text)$/i ) {
473 $size = 65_535;
256d534a 474 }
7898fb70 475 elsif ( $type =~ /^medium(blob|text)$/i ) {
476 $size = 16_777_215;
256d534a 477 }
7898fb70 478 elsif ( $type =~ /^long(blob|text)$/i ) {
479 $size = 4_294_967_295;
256d534a 480 }
481
d529894e 482 $return = {
483 type => $type,
484 size => $size,
485 list => $list,
486 qualifiers => $item[3],
487 }
488 }
16dc9970 489
658637cd 490parens_field_list : '(' field_name(s /,/) ')'
491 { $item[2] }
492
d529894e 493parens_value_list : '(' VALUE(s /,/) ')'
494 { $item[2] }
16dc9970 495
d529894e 496type_qualifier : /(BINARY|UNSIGNED|ZEROFILL)/i
497 { lc $item[1] }
16dc9970 498
d529894e 499field_type : WORD
16dc9970 500
d529894e 501create_index : /create/i /index/i
dd2ef5ae 502
e78d62f2 503not_null : /not/i /null/i
504 { $return = 0 }
505 |
506 /null/i
507 { $return = 1 }
16dc9970 508
d529894e 509unsigned : /unsigned/i { $return = 0 }
16dc9970 510
09fa21a6 511#default_val : /default/i /(?:')?[\s\w\d:.-]*(?:')?/
512# {
513# $item[2] =~ s/'//g;
514# $return = $item[2];
515# }
516
6fa97af6 517default_val :
518 /default/i 'CURRENT_TIMESTAMP'
519 {
520 $return = $item[2];
521 }
522 |
523 /default/i /'(?:.*?\\')*.*?'|(?:')?[\w\d:.-]*(?:')?/
09fa21a6 524 {
525 $item[2] =~ s/^\s*'|'\s*$//g;
d529894e 526 $return = $item[2];
527 }
16dc9970 528
d529894e 529auto_inc : /auto_increment/i { 1 }
16dc9970 530
d529894e 531primary_key : /primary/i /key/i { 1 }
16dc9970 532
f2cf1734 533constraint : primary_key_def
534 | unique_key_def
535 | foreign_key_def
536 | <error>
537
02a21f1a 538foreign_key_def : foreign_key_def_begin parens_field_list reference_definition
40c1ade1 539 {
540 $return = {
f2cf1734 541 supertype => 'constraint',
40c1ade1 542 type => 'foreign_key',
02a21f1a 543 name => $item[1],
09fa21a6 544 fields => $item[2],
40c1ade1 545 %{ $item{'reference_definition'} },
546 }
547 }
548
e78d62f2 549foreign_key_def_begin : /constraint/i /foreign key/i WORD
550 { $return = $item[3] }
551 |
552 /constraint/i NAME /foreign key/i
553 { $return = $item[2] }
554 |
555 /constraint/i /foreign key/i
02a21f1a 556 { $return = '' }
557 |
e78d62f2 558 /foreign key/i WORD
02a21f1a 559 { $return = $item[2] }
560 |
561 /foreign key/i
562 { $return = '' }
40c1ade1 563
1853ba82 564primary_key_def : primary_key index_name(?) '(' name_with_opt_paren(s /,/) ')'
d529894e 565 {
f2cf1734 566 $return = {
567 supertype => 'constraint',
568 name => $item{'index_name(?)'}[0],
569 type => 'primary_key',
570 fields => $item[4],
58a88238 571 };
d529894e 572 }
16dc9970 573
f2cf1734 574unique_key_def : UNIQUE KEY(?) index_name(?) '(' name_with_opt_paren(s /,/) ')'
d529894e 575 {
f2cf1734 576 $return = {
577 supertype => 'constraint',
578 name => $item{'index_name(?)'}[0],
579 type => 'unique',
580 fields => $item[5],
d529894e 581 }
582 }
16dc9970 583
f2cf1734 584normal_index : KEY index_name(?) '(' name_with_opt_paren(s /,/) ')'
d529894e 585 {
f2cf1734 586 $return = {
587 supertype => 'index',
588 type => 'normal',
589 name => $item{'index_name(?)'}[0],
590 fields => $item[4],
d529894e 591 }
592 }
16dc9970 593
f2cf1734 594fulltext_index : /fulltext/i KEY(?) index_name(?) '(' name_with_opt_paren(s /,/) ')'
371f5f88 595 {
f2cf1734 596 $return = {
597 supertype => 'index',
598 type => 'fulltext',
599 name => $item{'index_name(?)'}[0],
600 fields => $item[5],
371f5f88 601 }
602 }
603
d529894e 604name_with_opt_paren : NAME parens_value_list(s?)
605 { $item[2][0] ? "$item[1]($item[2][0][0])" : $item[1] }
16dc9970 606
f2cf1734 607UNIQUE : /unique/i { 1 }
16dc9970 608
f2cf1734 609KEY : /key/i | /index/i
16dc9970 610
e78d62f2 611table_option : 'DEFAULT CHARSET' /\s*=\s*/ WORD
612 {
613 $return = { $item[1] => $item[3] };
614 }
35843e6b 615 | /comment/i /=/ /'.*?'/
616 {
617 my $comment = $item[3];
618 $comment =~ s/^'//;
619 $comment =~ s/'$//;
620 $return = { comment => $comment };
621 }
e78d62f2 622 | WORD /\s*=\s*/ WORD
d529894e 623 {
02a21f1a 624 $return = { $item[1] => $item[3] };
d529894e 625 }
16dc9970 626
13aec984 627ADD : /add/i
628
629ALTER : /alter/i
630
40c1ade1 631CREATE : /create/i
632
633TEMPORARY : /temporary/i
634
635TABLE : /table/i
636
d529894e 637WORD : /\w+/
16dc9970 638
d529894e 639DIGITS : /\d+/
16dc9970 640
d529894e 641COMMA : ','
16dc9970 642
d529894e 643NAME : "`" /\w+/ "`"
644 { $item[2] }
645 | /\w+/
646 { $item[1] }
16dc9970 647
d529894e 648VALUE : /[-+]?\.?\d+(?:[eE]\d+)?/
649 { $item[1] }
f2cf1734 650 | /'.*?'/
651 {
652 # remove leading/trailing quotes
653 my $val = $item[1];
654 $val =~ s/^['"]|['"]$//g;
655 $return = $val;
656 }
d529894e 657 | /NULL/
658 { 'NULL' }
16dc9970 659
d529894e 660!;
16dc9970 661
d529894e 662# -------------------------------------------------------------------
663sub parse {
70944bc5 664 my ( $translator, $data ) = @_;
40c1ade1 665 my $parser = Parse::RecDescent->new($GRAMMAR);
077ebf34 666
e099bee9 667 local $::RD_TRACE = $translator->trace ? 1 : undef;
668 local $DEBUG = $translator->debug;
d529894e 669
670 unless (defined $parser) {
671 return $translator->error("Error instantiating Parse::RecDescent ".
672 "instance: Bad grammer");
673 }
674
675 my $result = $parser->startrule($data);
40c1ade1 676 return $translator->error( "Parse failed." ) unless defined $result;
13aec984 677 warn "Parse result:".Dumper( $result ) if $DEBUG;
8ccdeb42 678
70944bc5 679 my $schema = $translator->schema;
13aec984 680 $schema->name($result->{'database_name'}) if $result->{'database_name'};
681
034ecdec 682 my @tables = sort {
13aec984 683 $result->{'tables'}{ $a }{'order'}
684 <=>
685 $result->{'tables'}{ $b }{'order'}
686 } keys %{ $result->{'tables'} };
034ecdec 687
688 for my $table_name ( @tables ) {
13aec984 689 my $tdata = $result->{tables}{ $table_name };
8ccdeb42 690 my $table = $schema->add_table(
691 name => $tdata->{'table_name'},
40c1ade1 692 ) or die $schema->error;
8ccdeb42 693
734dfc91 694 $table->comments( $tdata->{'comments'} );
f2cf1734 695
8ccdeb42 696 my @fields = sort {
697 $tdata->{'fields'}->{$a}->{'order'}
698 <=>
699 $tdata->{'fields'}->{$b}->{'order'}
700 } keys %{ $tdata->{'fields'} };
701
702 for my $fname ( @fields ) {
703 my $fdata = $tdata->{'fields'}{ $fname };
704 my $field = $table->add_field(
705 name => $fdata->{'name'},
706 data_type => $fdata->{'data_type'},
707 size => $fdata->{'size'},
708 default_value => $fdata->{'default'},
709 is_auto_increment => $fdata->{'is_auto_inc'},
710 is_nullable => $fdata->{'null'},
88b89793 711 comments => $fdata->{'comments'},
40c1ade1 712 ) or die $table->error;
f2cf1734 713
714 $table->primary_key( $field->name ) if $fdata->{'is_primary_key'};
715
716 for my $qual ( qw[ binary unsigned zerofill list ] ) {
717 if ( my $val = $fdata->{ $qual } || $fdata->{ uc $qual } ) {
718 next if ref $val eq 'ARRAY' && !@$val;
719 $field->extra( $qual, $val );
720 }
721 }
722
723 if ( $field->data_type =~ /(set|enum)/i && !$field->size ) {
724 my %extra = $field->extra;
d14fe688 725 my $longest = 0;
f2cf1734 726 for my $len ( map { length } @{ $extra{'list'} || [] } ) {
727 $longest = $len if $len > $longest;
728 }
729 $field->size( $longest ) if $longest;
730 }
731
732 for my $cdata ( @{ $fdata->{'constraints'} } ) {
733 next unless $cdata->{'type'} eq 'foreign_key';
734 $cdata->{'fields'} ||= [ $field->name ];
735 push @{ $tdata->{'constraints'} }, $cdata;
736 }
737 }
738
739 for my $idata ( @{ $tdata->{'indices'} || [] } ) {
740 my $index = $table->add_index(
741 name => $idata->{'name'},
742 type => uc $idata->{'type'},
743 fields => $idata->{'fields'},
744 ) or die $table->error;
745 }
746
02a21f1a 747 if ( my @options = @{ $tdata->{'table_options'} || [] } ) {
748 $table->options( \@options ) or die $table->error;
749 }
750
f2cf1734 751 for my $cdata ( @{ $tdata->{'constraints'} || [] } ) {
752 my $constraint = $table->add_constraint(
753 name => $cdata->{'name'},
754 type => $cdata->{'type'},
755 fields => $cdata->{'fields'},
756 reference_table => $cdata->{'reference_table'},
757 reference_fields => $cdata->{'reference_fields'},
758 match_type => $cdata->{'match_type'} || '',
759 on_delete => $cdata->{'on_delete_do'},
760 on_update => $cdata->{'on_update_do'},
761 ) or die $table->error;
8ccdeb42 762 }
763 }
764
f62bd16c 765 return 1;
d529894e 766}
767
7681;
769
034ecdec 770# -------------------------------------------------------------------
d529894e 771# Where man is not nature is barren.
772# William Blake
034ecdec 773# -------------------------------------------------------------------
16dc9970 774
d529894e 775=pod
16dc9970 776
777=head1 AUTHOR
778
d529894e 779Ken Y. Clark E<lt>kclark@cpan.orgE<gt>,
8ccdeb42 780Chris Mungall E<lt>cjm@fruitfly.orgE<gt>.
16dc9970 781
782=head1 SEE ALSO
783
8ccdeb42 784perl(1), Parse::RecDescent, SQL::Translator::Schema.
16dc9970 785
786=cut