use strict;
use warnings;
-our ( $DEBUG, $GRAMMAR, @EXPORT_OK );
+
our $VERSION = '1.59';
+
+our $DEBUG;
$DEBUG = 0 unless defined $DEBUG;
use Data::Dumper;
-use Parse::RecDescent;
-use Exporter;
use Storable qw(dclone);
use DBI qw(:sql_types);
-use base qw(Exporter);
+use SQL::Translator::Utils qw/parse_mysql_version ddl_parser_instance/;
-use SQL::Translator::Utils qw/parse_mysql_version/;
+use base qw(Exporter);
+our @EXPORT_OK = qw(parse);
our %type_mapping = ();
-@EXPORT_OK = qw(parse);
-
-# Enable warnings within the Parse::RecDescent module.
-$::RD_ERRORS = 1; # Make sure the parser dies when it encounters an error
-$::RD_WARN = 1; # Enable warnings. This will warn on unused rules &c.
-$::RD_HINT = 1; # Give out hints to help fix problems.
-
use constant DEFAULT_PARSER_VERSION => 30000;
-$GRAMMAR = << 'END_OF_GRAMMAR';
+our $GRAMMAR = << 'END_OF_GRAMMAR';
{
my ( $database_name, %tables, $table_order, @table_comments, %views,
{ @table_comments = () }
bit:
- /(b'[01]+')/ |
- /(b"[01]+")/
+ /(b'[01]{1,64}')/ |
+ /(b"[01]{1,64}")/
string :
# MySQL strings, unlike common SQL strings, can be double-quoted or
{ $item[2] }
on_update :
- /on update/i 'CURRENT_TIMESTAMP'
+ /on update/i CURRENT_TIMESTAMP
{ $item[2] }
|
/on update/i reference_option
unsigned : /unsigned/i { $return = 0 }
default_val :
- /default/i 'CURRENT_TIMESTAMP'
+ /default/i CURRENT_TIMESTAMP
{
- $return = \$item[2];
+ $return = $item[2];
}
|
/default/i string
$return = $item[2];
}
|
- /default/i /(?:')?[\w\d:.-]*(?:')?/
+ /default/i /[\w\d:.-]+/
{
$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],
};
}
| /NULL/
{ 'NULL' }
-CURRENT_TIMESTAMP : /current_timestamp(\(\))?/i
- | /now\(\)/i
- { 'CURRENT_TIMESTAMP' }
+# always a scalar-ref, so that it is treated as a function and not quoted by consumers
+CURRENT_TIMESTAMP :
+ /current_timestamp(\(\))?/i { \'CURRENT_TIMESTAMP' }
+ | /now\(\)/i { \'CURRENT_TIMESTAMP' }
END_OF_GRAMMAR
sub parse {
my ( $translator, $data ) = @_;
- my $parser = Parse::RecDescent->new($GRAMMAR);
+
+ # Enable warnings within the Parse::RecDescent module.
+ local $::RD_ERRORS = 1 unless defined $::RD_ERRORS; # Make sure the parser dies when it encounters an error
+ local $::RD_WARN = 1 unless defined $::RD_WARN; # Enable warnings. This will warn on unused rules &c.
+ local $::RD_HINT = 1 unless defined $::RD_HINT; # Give out hints to help fix problems.
+
local $::RD_TRACE = $translator->trace ? 1 : undef;
local $DEBUG = $translator->debug;
- unless (defined $parser) {
- return $translator->error("Error instantiating Parse::RecDescent ".
- "instance: Bad grammer");
- }
+ my $parser = ddl_parser_instance('MySQL');
# Preprocess for MySQL-specific and not-before-version comments
# from mysqldump
# 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;