package SQL::Translator::Parser::MySQL;
-# -------------------------------------------------------------------
-# Copyright (C) 2002-2009 SQLFairy Authors
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License as
-# published by the Free Software Foundation; version 2.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
-# 02111-1307 USA
-# -------------------------------------------------------------------
-
=head1 NAME
SQL::Translator::Parser::MySQL - parser for MySQL
=cut
use strict;
-use vars qw[ $DEBUG $VERSION $GRAMMAR @EXPORT_OK ];
-$VERSION = '1.59';
+use warnings;
+our ( $DEBUG, $GRAMMAR, @EXPORT_OK );
+our $VERSION = '1.59';
$DEBUG = 0 unless defined $DEBUG;
use Data::Dumper;
drop : /drop/i WORD(s) "$delimiter"
{ @table_comments = () }
+bit:
+ /(b'[01]+')/ |
+ /(b"[01]+")/
+
string :
# MySQL strings, unlike common SQL strings, can be double-quoted or
# single-quoted, and you can escape the delmiters by doubling (but only the
create : CREATE TEMPORARY(?) TABLE opt_if_not_exists(?) table_name '(' create_definition(s /,/) /(,\s*)?\)/ table_option(s?) "$delimiter"
{
my $table_name = $item{'table_name'};
+ die "There is more than one definition for $table_name"
+ if ($tables{$table_name});
+
$tables{ $table_name }{'order'} = ++$table_order;
$tables{ $table_name }{'table_name'} = $table_name;
$return = \$item[2];
}
|
- /default/i /'(?:.*?(?:\\'|''))*.*?'|(?:')?[\w\d:.-]*(?:')?/
+ /default/i string
+ {
+ $item[2] =~ s/^\s*'|'\s*$//g or $item[2] =~ s/^\s*"|"\s*$//g;
+ $return = $item[2];
+ }
+ |
+ /default/i bit
+ {
+ $item[2] =~ s/b['"]([01]+)['"]/$1/g;
+ $return = $item[2];
+ }
+ |
+ /default/i /[\w\d:.-]+/
{
- $item[2] =~ s/^\s*'|'\s*$//g;
$return = $item[2];
}
/foreign key/i
{ $return = '' }
-primary_key_def : primary_key index_name_not_using(?) index_type(?) '(' name_with_opt_paren(s /,/) ')' index_type(?)
+primary_key_def : primary_key index_type(?) '(' name_with_opt_paren(s /,/) ')' index_type(?)
{
$return = {
supertype => 'constraint',
- name => $item[2][0],
type => 'primary_key',
- fields => $item[5],
- options => $item[3][0] || $item[7][0],
+ fields => $item[4],
+ options => $item[2][0] || $item[6][0],
+ };
+ }
+ # In theory, and according to the doc, names should not be allowed here, but
+ # MySQL accept (and ignores) them, so we are not going to be less :)
+ | primary_key index_name_not_using(?) '(' name_with_opt_paren(s /,/) ')' index_type(?)
+ {
+ $return = {
+ supertype => 'constraint',
+ type => 'primary_key',
+ fields => $item[4],
+ options => $item[6][0],
};
}
END_OF_GRAMMAR
-# -------------------------------------------------------------------
sub parse {
my ( $translator, $data ) = @_;
my $parser = Parse::RecDescent->new($GRAMMAR);
# Takes a field, and returns
sub normalize_field {
my ($field) = @_;
- my ($size, $type, $list, $changed) = @_;
+ my ($size, $type, $list, $unsigned, $changed);
$size = $field->size;
$type = $field->data_type;
$list = $field->extra->{list} || [];
+ $unsigned = defined($field->extra->{unsigned});
if ( !ref $size && $size eq 0 ) {
if ( lc $type eq 'tinyint' ) {
- $changed = $size != 4;
- $size = 4;
+ $changed = $size != 4 - $unsigned;
+ $size = 4 - $unsigned;
}
elsif ( lc $type eq 'smallint' ) {
- $changed = $size != 6;
- $size = 6;
+ $changed = $size != 6 - $unsigned;
+ $size = 6 - $unsigned;
}
elsif ( lc $type eq 'mediumint' ) {
- $changed = $size != 9;
- $size = 9;
+ $changed = $size != 9 - $unsigned;
+ $size = 9 - $unsigned;
}
elsif ( $type =~ /^int(eger)?$/i ) {
- $changed = $size != 11 || $type ne 'int';
+ $changed = $size != 11 - $unsigned || $type ne 'int';
$type = 'int';
- $size = 11;
+ $size = 11 - $unsigned;
}
elsif ( lc $type eq 'bigint' ) {
$changed = $size != 20;