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