From: Mark Addison Date: Thu, 25 Nov 2004 22:32:48 +0000 (+0000) Subject: Applied Dave Howorth's MySQL parser patches X-Git-Tag: v0.11008~593 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=13aec9843503aacfdcfd8cf11f6d14305ece2431;p=dbsrgits%2FSQL-Translator.git Applied Dave Howorth's MySQL parser patches - ignore INSERT statements - permit ALTER TABLE ADD FOREIGN KEY - allow trailing comma on last field in CREATE statements - collect the database name --- diff --git a/Changes b/Changes index 51639e7..120ee4a 100644 --- a/Changes +++ b/Changes @@ -4,6 +4,12 @@ * Refactoring: Added SQL::Translator::Schema::Object - base class for all Schema objects. +* Changes to MySQL Parser (Dave Howorth) + - ignore INSERT statements + - permit ALTER TABLE ADD FOREIGN KEY + - allow trailing comma on last field in CREATE statements + - collect the database name + # ----------------------------------------------------------- # 0.06 2004-05-13 # ----------------------------------------------------------- diff --git a/lib/SQL/Translator/Parser/MySQL.pm b/lib/SQL/Translator/Parser/MySQL.pm index c0a2144..69ad29f 100644 --- a/lib/SQL/Translator/Parser/MySQL.pm +++ b/lib/SQL/Translator/Parser/MySQL.pm @@ -1,7 +1,7 @@ package SQL::Translator::Parser::MySQL; # ------------------------------------------------------------------- -# $Id: MySQL.pm,v 1.44 2004-03-01 17:39:22 kycl4rk Exp $ +# $Id: MySQL.pm,v 1.45 2004-11-25 22:32:48 grommit Exp $ # ------------------------------------------------------------------- # Copyright (C) 2002-4 SQLFairy Authors # @@ -117,11 +117,24 @@ Here's the word from the MySQL site or DATA DIRECTORY="absolute path to directory" or INDEX DIRECTORY="absolute path to directory" +A subset of the ALTER TABLE syntax that allows addition of foreign keys: + + ALTER [IGNORE] TABLE tbl_name alter_specification [, alter_specification] ... + + alter_specification: + ADD [CONSTRAINT [symbol]] + FOREIGN KEY [index_name] (index_col_name,...) + [reference_definition] + +A subset of INSERT that we ignore: + + INSERT anything + =cut use strict; use vars qw[ $DEBUG $VERSION $GRAMMAR @EXPORT_OK ]; -$VERSION = sprintf "%d.%02d", q$Revision: 1.44 $ =~ /(\d+)\.(\d+)/; +$VERSION = sprintf "%d.%02d", q$Revision: 1.45 $ =~ /(\d+)\.(\d+)/; $DEBUG = 0 unless defined $DEBUG; use Data::Dumper; @@ -139,7 +152,7 @@ $::RD_HINT = 1; # Give out hints to help fix problems. $GRAMMAR = q! { - my ( %tables, $table_order, @table_comments ); + my ( $database_name, %tables, $table_order, @table_comments ); } # @@ -148,7 +161,9 @@ $GRAMMAR = q! # won't cause the failure needed to know that the parse, as a whole, # failed. -ky # -startrule : statement(s) eofile { \%tables } +startrule : statement(s) eofile { + { tables => \%tables, database_name => $database_name } +} eofile : /^\Z/ @@ -157,10 +172,15 @@ statement : comment | set | drop | create + | alter + | insert | use : /use/i WORD ';' - { @table_comments = () } + { + $database_name = $item[2]; + @table_comments = (); + } set : /set/i /[^;]+/ ';' { @table_comments = () } @@ -170,10 +190,26 @@ drop : /drop/i TABLE /[^;]+/ ';' drop : /drop/i WORD(s) ';' { @table_comments = () } +insert : /insert/i /[^;]+/ ';' + +alter : ALTER TABLE table_name alter_specification(s /,/) ';' + { + my $table_name = $item{'table_name'}; + die "Cannot ALTER table '$table_name'; it does not exist" + unless $tables{ $table_name }; + for my $definition ( @{ $item[4] } ) { + $definition->{'extra'}->{'alter'} = 1; + push @{ $tables{ $table_name }{'constraints'} }, $definition; + } + } + +alter_specification : ADD foreign_key_def + { $return = $item[2] } + create : CREATE /database/i WORD ';' { @table_comments = () } -create : CREATE TEMPORARY(?) TABLE opt_if_not_exists(?) table_name '(' create_definition(s /,/) ')' table_option(s?) ';' +create : CREATE TEMPORARY(?) TABLE opt_if_not_exists(?) table_name '(' create_definition(s /,/) /(,\s*)?\)/ table_option(s?) ';' { my $table_name = $item{'table_name'}; $tables{ $table_name }{'order'} = ++$table_order; @@ -533,6 +569,10 @@ table_option : WORD /\s*=\s*/ WORD $return = { $item[1] => $item[3] }; } +ADD : /add/i + +ALTER : /alter/i + CREATE : /create/i TEMPORARY : /temporary/i @@ -579,15 +619,19 @@ sub parse { my $result = $parser->startrule($data); return $translator->error( "Parse failed." ) unless defined $result; - warn Dumper( $result ) if $DEBUG; + warn "Parse result:".Dumper( $result ) if $DEBUG; my $schema = $translator->schema; + $schema->name($result->{'database_name'}) if $result->{'database_name'}; + my @tables = sort { - $result->{ $a }->{'order'} <=> $result->{ $b }->{'order'} - } keys %{ $result }; + $result->{'tables'}{ $a }{'order'} + <=> + $result->{'tables'}{ $b }{'order'} + } keys %{ $result->{'tables'} }; for my $table_name ( @tables ) { - my $tdata = $result->{ $table_name }; + my $tdata = $result->{tables}{ $table_name }; my $table = $schema->add_table( name => $tdata->{'table_name'}, ) or die $schema->error; diff --git a/t/02mysql-parser.t b/t/02mysql-parser.t index 1839795..64c3c1b 100644 --- a/t/02mysql-parser.t +++ b/t/02mysql-parser.t @@ -10,7 +10,7 @@ use SQL::Translator::Schema::Constants; use Test::SQL::Translator qw(maybe_plan); BEGIN { - maybe_plan(180, "SQL::Translator::Parser::MySQL"); + maybe_plan(199, "SQL::Translator::Parser::MySQL"); SQL::Translator::Parser::MySQL->import('parse'); } @@ -389,3 +389,77 @@ BEGIN { my @t2_fields = $t2->get_fields; is( scalar @t2_fields, 8, 'Right number of fields (8)' ); } + +# djh Tests for: +# USE database ; +# ALTER TABLE ADD FOREIGN KEY +# trailing comma on last create definition +# Ignoring INSERT statements +# +{ + my $tr = SQL::Translator->new; + my $data = parse($tr, + q[ + USE database_name; + + CREATE TABLE one ( + id integer NOT NULL auto_increment, + two_id integer NOT NULL auto_increment, + some_data text, + PRIMARY KEY (id), + INDEX (two_id), + ) TYPE=INNODB; + + CREATE TABLE two ( + id int NOT NULL auto_increment, + one_id int NOT NULL auto_increment, + some_data text, + PRIMARY KEY (id), + INDEX (one_id), + FOREIGN KEY (one_id) REFERENCES one (id), + ) TYPE=INNODB; + + ALTER TABLE one ADD FOREIGN KEY (two_id) REFERENCES two (id); + + INSERT absolutely *#! any old $£ ? rubbish ; + ] + ) or die $tr->error; + + my $schema = $tr->schema; + is( $schema->is_valid, 1, 'Schema is valid' ); + my $db_name = $schema->name; + is( $db_name, 'database_name', 'Database name extracted from USE' ); + my @tables = $schema->get_tables; + is( scalar @tables, 2, 'Right number of tables (2)' ); + my $table1 = shift @tables; + is( $table1->name, 'one', 'Found "one" table' ); + my $table2 = shift @tables; + is( $table2->name, 'two', 'Found "two" table' ); + + my @constraints = $table1->get_constraints; + is(scalar @constraints, 2, 'Right number of constraints (2) on table one'); + + my $t1c1 = shift @constraints; + is( $t1c1->type, PRIMARY_KEY, 'Constraint is a PK' ); + is( join(',', $t1c1->fields), 'id', 'Constraint is on "id"' ); + + my $t1c2 = shift @constraints; + is( $t1c2->type, FOREIGN_KEY, 'Constraint is a FK' ); + is( join(',', $t1c2->fields), 'two_id', 'Constraint is on "two_id"' ); + is( $t1c2->reference_table, 'two', 'To table "two"' ); + is( join(',', $t1c2->reference_fields), 'id', 'To field "id"' ); + + @constraints = $table2->get_constraints; + is(scalar @constraints, 2, 'Right number of constraints (2) on table two'); + + my $t2c1 = shift @constraints; + is( $t2c1->type, PRIMARY_KEY, 'Constraint is a PK' ); + is( join(',', $t2c1->fields), 'id', 'Constraint is on "id"' ); + + my $t2c2 = shift @constraints; + is( $t2c2->type, FOREIGN_KEY, 'Constraint is a FK' ); + is( join(',', $t2c2->fields), 'one_id', 'Constraint is on "one_id"' ); + is( $t2c2->reference_table, 'one', 'To table "one"' ); + is( join(',', $t2c2->reference_fields), 'id', 'To field "id"' ); +} +