* 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
# -----------------------------------------------------------
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
#
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;
$GRAMMAR = q!
{
- my ( %tables, $table_order, @table_comments );
+ my ( $database_name, %tables, $table_order, @table_comments );
}
#
# 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/
| set
| drop
| create
+ | alter
+ | insert
| <error>
use : /use/i WORD ';'
- { @table_comments = () }
+ {
+ $database_name = $item[2];
+ @table_comments = ();
+ }
set : /set/i /[^;]+/ ';'
{ @table_comments = () }
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;
$return = { $item[1] => $item[3] };
}
+ADD : /add/i
+
+ALTER : /alter/i
+
CREATE : /create/i
TEMPORARY : /temporary/i
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;
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');
}
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"' );
+}
+