X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FSQL%2FTranslator%2FParser%2FMySQL.pm;h=5383f74e2deb1364c8b39313806acce6fc32d5fc;hb=ba506e52c480afe33dfec6b38a12759fad1e7fa2;hp=db556043e691f6c053eda276854f5a2859ff1de0;hpb=4ab3763d2ad756c236b757306989cafa08e7f35e;p=dbsrgits%2FSQL-Translator.git diff --git a/lib/SQL/Translator/Parser/MySQL.pm b/lib/SQL/Translator/Parser/MySQL.pm index db55604..5383f74 100644 --- a/lib/SQL/Translator/Parser/MySQL.pm +++ b/lib/SQL/Translator/Parser/MySQL.pm @@ -147,7 +147,7 @@ More information about the MySQL comment-syntax: L 30000; $GRAMMAR = << 'END_OF_GRAMMAR'; { - my ( $database_name, %tables, $table_order, @table_comments, %views, $view_order, %procedures, $proc_order ); + my ( $database_name, %tables, $table_order, @table_comments, %views, + $view_order, %procedures, $proc_order ); my $delimiter = ';'; } @@ -185,7 +185,12 @@ $GRAMMAR = << 'END_OF_GRAMMAR'; # failed. -ky # startrule : statement(s) eofile { - { tables => \%tables, database_name => $database_name, views => \%views, procedures =>\%procedures } + { + database_name => $database_name, + tables => \%tables, + views => \%views, + procedures => \%procedures, + } } eofile : /^\Z/ @@ -226,9 +231,9 @@ string : nonstring : /[^;\'"]+/ -statement_body : (string | nonstring)(s?) +statement_body : string | nonstring -insert : /insert/i statement_body "$delimiter" +insert : /insert/i statement_body(s?) "$delimiter" delimiter : /delimiter/i /[\S]+/ { $delimiter = $item[2] } @@ -338,11 +343,12 @@ create : CREATE PROCEDURE NAME not_delimiter "$delimiter" PROCEDURE : /procedure/i | /function/i -create : CREATE algorithm /view/i NAME not_delimiter "$delimiter" +create : CREATE replace(?) algorithm(?) /view/i NAME not_delimiter "$delimiter" { @table_comments = (); - my $view_name = $item[4]; - my $sql = "$item[1] $item[2] $item[3] $item[4] $item[5]"; + my $view_name = $item[5]; + my $sql = join(q{ }, grep { defined and length } $item[1], $item[2]->[0], $item[3]->[0]) + . " $item[4] $item[5] $item[6]"; # Hack to strip database from function calls in SQL $sql =~ s#`\w+`\.(`\w+`\()##g; @@ -352,6 +358,8 @@ create : CREATE algorithm /view/i NAME not_delimiter "$delimiter" $views{ $view_name }{'sql'} = $sql; } +replace : /or replace/i + algorithm : /algorithm/i /=/ WORD { $return = "$item[1]=$item[3]"; @@ -586,19 +594,13 @@ not_null : /not/i /null/i unsigned : /unsigned/i { $return = 0 } -#default_val : /default/i /(?:')?[\s\w\d:.-]*(?:')?/ -# { -# $item[2] =~ s/'//g; -# $return = $item[2]; -# } - default_val : /default/i 'CURRENT_TIMESTAMP' { $return = \$item[2]; } | - /default/i /'(?:.*?\\')*.*?'|(?:')?[\w\d:.-]*(?:')?/ + /default/i /'(?:.*?(?:\\'|''))*.*?'|(?:')?[\w\d:.-]*(?:')?/ { $item[2] =~ s/^\s*'|'\s*$//g; $return = $item[2]; @@ -659,16 +661,22 @@ unique_key_def : UNIQUE KEY(?) index_name(?) '(' name_with_opt_paren(s /,/) ')' } } -normal_index : KEY index_name(?) '(' name_with_opt_paren(s /,/) ')' +normal_index : KEY index_name_not_using(?) index_type(?) '(' name_with_opt_paren(s /,/) ')' { $return = { supertype => 'index', type => 'normal', - name => $item{'index_name(?)'}[0], - fields => $item[4], + name => $item[2][0], + fields => $item[5], + options => $item[3][0], } } +index_name_not_using : QUOTED_NAME + | /(\b(?!using)\w+\b)/ { $return = $1 } + +index_type : /using (btree|hash|rtree)/i { $return = uc $1 } + fulltext_index : /fulltext/i KEY(?) index_name(?) '(' name_with_opt_paren(s /,/) ')' { $return = { @@ -715,11 +723,17 @@ table_option : /comment/i /=/ /'.*?'/ { $return = { $item[1] => $item[4] }; } - | WORD /\s*=\s*/ WORD - { + | WORD /\s*=\s*/ MAYBE_QUOTED_WORD + { $return = { $item[1] => $item[3] }; } - + +MAYBE_QUOTED_WORD: /\w+/ + | /'(\w+)'/ + { $return = $1 } + | /"(\w+)"/ + { $return = $1 } + default : /default/i ADD : /add/i @@ -740,12 +754,17 @@ COMMA : ',' BACKTICK : '`' -NAME : BACKTICK /[^`]+/ BACKTICK +DOUBLE_QUOTE: '"' + +QUOTED_NAME : BACKTICK /[^`]+/ BACKTICK + { $item[2] } + | DOUBLE_QUOTE /[^"]+/ DOUBLE_QUOTE { $item[2] } - | /\w+/ - { $item[1] } -VALUE : /[-+]?\.?\d+(?:[eE]\d+)?/ +NAME: QUOTED_NAME + | /\w+/ + +VALUE : /[-+]?\.?\d+(?:[eE]\d+)?/ { $item[1] } | /'.*?'/ { @@ -775,11 +794,17 @@ sub parse { "instance: Bad grammer"); } - # Preprocess for MySQL-specific and not-before-version comments from mysqldump - my $parser_version = - parse_mysql_version ($translator->parser_args->{mysql_parser_version}, 'mysql') - || DEFAULT_PARSER_VERSION; - while ( $data =~ s#/\*!(\d{5})?(.*?)\*/#($1 && $1 > $parser_version ? '' : $2)#es ) {} + # Preprocess for MySQL-specific and not-before-version comments + # from mysqldump + my $parser_version = parse_mysql_version( + $translator->parser_args->{mysql_parser_version}, 'mysql' + ) || DEFAULT_PARSER_VERSION; + + while ( $data =~ + s#/\*!(\d{5})?(.*?)\*/#($1 && $1 > $parser_version ? '' : $2)#es + ) { + # do nothing; is there a better way to write this? -- ky + } my $result = $parser->startrule($data); return $translator->error( "Parse failed." ) unless defined $result; @@ -864,13 +889,17 @@ sub parse { if ( my @options = @{ $tdata->{'table_options'} || [] } ) { my @cleaned_options; - my @ignore_opts = $translator->parser_args->{ignore_opts}?split(/,/,$translator->parser_args->{ignore_opts}):(); + my @ignore_opts = $translator->parser_args->{'ignore_opts'} + ? split( /,/, $translator->parser_args->{'ignore_opts'} ) + : (); if (@ignore_opts) { my $ignores = { map { $_ => 1 } @ignore_opts }; foreach my $option (@options) { # make sure the option isn't in ignore list my ($option_key) = keys %$option; - push(@cleaned_options, $option) unless (exists $ignores->{$option_key}); + if ( !exists $ignores->{$option_key} ) { + push @cleaned_options, $option; + } } } else { @cleaned_options = @options; @@ -886,19 +915,25 @@ sub parse { reference_table => $cdata->{'reference_table'}, reference_fields => $cdata->{'reference_fields'}, match_type => $cdata->{'match_type'} || '', - on_delete => $cdata->{'on_delete'} || $cdata->{'on_delete_do'}, - on_update => $cdata->{'on_update'} || $cdata->{'on_update_do'}, + on_delete => $cdata->{'on_delete'} + || $cdata->{'on_delete_do'}, + on_update => $cdata->{'on_update'} + || $cdata->{'on_update_do'}, ) or die $table->error; } - # After the constrains and PK/idxs have been created, we normalize fields + # After the constrains and PK/idxs have been created, + # we normalize fields normalize_field($_) for $table->get_fields; } my @procedures = sort { - $result->{procedures}->{ $a }->{'order'} <=> $result->{procedures}->{ $b }->{'order'} + $result->{procedures}->{ $a }->{'order'} + <=> + $result->{procedures}->{ $b }->{'order'} } keys %{ $result->{procedures} }; - foreach my $proc_name (@procedures) { + + for my $proc_name ( @procedures ) { $schema->add_procedure( name => $proc_name, owner => $result->{procedures}->{$proc_name}->{owner}, @@ -907,12 +942,15 @@ sub parse { } my @views = sort { - $result->{views}->{ $a }->{'order'} <=> $result->{views}->{ $b }->{'order'} + $result->{views}->{ $a }->{'order'} + <=> + $result->{views}->{ $b }->{'order'} } keys %{ $result->{views} }; - foreach my $view_name (keys %{ $result->{views} }) { + + for my $view_name ( keys %{ $result->{'views'} } ) { $schema->add_view( name => $view_name, - sql => $result->{views}->{$view_name}->{sql}, + sql => $result->{'views'}->{$view_name}->{sql}, ); } @@ -952,8 +990,10 @@ sub normalize_field { } elsif ( lc $type =~ /(float|double|decimal|numeric|real|fixed|dec)/ ) { my $old_size = (ref $size || '') eq 'ARRAY' ? $size : []; - $changed = @$old_size != 2 || $old_size->[0] != 8 || $old_size->[1] != 2; - $size = [8,2]; + $changed = @$old_size != 2 + || $old_size->[0] != 8 + || $old_size->[1] != 2; + $size = [8,2]; } } @@ -973,6 +1013,7 @@ sub normalize_field { $changed = $size != 4_294_967_295; $size = 4_294_967_295; } + if ( $field->data_type =~ /(set|enum)/i && !$field->size ) { my %extra = $field->extra; my $longest = 0; @@ -984,20 +1025,21 @@ sub normalize_field { } - if ($changed) { - # We only want to clone the field, not *everything* - { local $field->{table} = undef; - $field->parsed_field(dclone($field)); - $field->parsed_field->{table} = $field->table; - } - $field->size($size); - $field->data_type($type); - $field->sql_data_type( $type_mapping{lc $type} ) if exists $type_mapping{lc $type}; - $field->extra->{list} = $list if @$list; + if ( $changed ) { + # We only want to clone the field, not *everything* + { + local $field->{table} = undef; + $field->parsed_field( dclone( $field ) ); + $field->parsed_field->{table} = $field->table; + } + $field->size( $size ); + $field->data_type( $type ); + $field->sql_data_type( $type_mapping{ lc $type } ) + if exists $type_mapping{ lc $type }; + $field->extra->{list} = $list if @$list; } } - 1; # -------------------------------------------------------------------