diff --git a/lib/SQL/Translator/Parser/MySQL.pm b/lib/SQL/Translator/Parser/MySQL.pm index df63744d7..eedf5839a 100644 --- a/lib/SQL/Translator/Parser/MySQL.pm +++ b/lib/SQL/Translator/Parser/MySQL.pm @@ -692,6 +692,11 @@ default_val : { $return = $item[2]; } + | + /default/i NAME # column value, allowed in MariaDB + { + $return = $item[2]; + } auto_inc : /auto_increment/i { 1 } @@ -700,8 +705,31 @@ primary_key : /primary/i /key/i { 1 } constraint : primary_key_def | unique_key_def | foreign_key_def + | check_def | +expr : /[^)]* \( [^)]+ \) [^)]*/x # parens, balanced one deep + | /[^)]+/ + +check_def : check_def_begin '(' expr ')' + { + $return = { + supertype => 'constraint', + type => 'check', + name => $item[1], + expression => $item[3], + } + } + +check_def_begin : /constraint/i /check/i NAME + { $return = $item[3] } + | + /constraint/i NAME /check/i + { $return = $item[2] } + | + /constraint/i /check/i + { $return = '' } + foreign_key_def : foreign_key_def_begin parens_field_list reference_definition { $return = { @@ -1017,6 +1045,7 @@ sub parse { name => $cdata->{'name'}, type => $cdata->{'type'}, fields => $cdata->{'fields'}, + expression => $cdata->{'expression'}, reference_table => $cdata->{'reference_table'}, reference_fields => $cdata->{'reference_fields'}, match_type => $cdata->{'match_type'} || '', diff --git a/lib/SQL/Translator/Parser/SQLite.pm b/lib/SQL/Translator/Parser/SQLite.pm index d1c7b6fff..8f09464b2 100644 --- a/lib/SQL/Translator/Parser/SQLite.pm +++ b/lib/SQL/Translator/Parser/SQLite.pm @@ -477,7 +477,8 @@ column_list : field_name(s /,/) parens_value_list : '(' VALUE(s /,/) ')' { $item[2] } -expr : /[^)]+/ +expr : /[^)]* \( [^)]+ \) [^)]*/x # parens, balanced one deep + | /[^)]+/ sort_order : /(ASC|DESC)/i diff --git a/lib/SQL/Translator/Producer/MySQL.pm b/lib/SQL/Translator/Producer/MySQL.pm index c8586a93f..5106dfb3e 100644 --- a/lib/SQL/Translator/Producer/MySQL.pm +++ b/lib/SQL/Translator/Producer/MySQL.pm @@ -716,7 +716,7 @@ sub alter_drop_constraint push @out, $c->type; } else { - push @out, ($c->type eq FOREIGN_KEY ? $c->type : "INDEX"), + push @out, ($c->type eq FOREIGN_KEY ? $c->type : "CONSTRAINT"), $generator->quote($c->name); } return join(' ',@out); @@ -743,12 +743,14 @@ sub create_constraint my $reference_table_name = $generator->quote($c->reference_table); - my @fields = $c->fields or return; + my @fields = $c->fields; if ( $c->type eq PRIMARY_KEY ) { + return unless @fields; return 'PRIMARY KEY (' . join(", ", map { $generator->quote($_) } @fields) . ')'; } elsif ( $c->type eq UNIQUE ) { + return unless @fields; return sprintf 'UNIQUE %s(%s)', ((defined $c->name && $c->name) ? $generator->quote( @@ -760,6 +762,7 @@ sub create_constraint ; } elsif ( $c->type eq FOREIGN_KEY ) { + return unless @fields; # # Make sure FK field is indexed or MySQL complains. # @@ -813,6 +816,20 @@ sub create_constraint } return $def; } + elsif ( $c->type eq CHECK_C ) { + my $table = $c->table; + my $c_name = truncate_id_uniquely( $c->name, $options->{max_id_length} || $DEFAULT_MAX_ID_LENGTH ); + + my $def = join(' ', + 'CONSTRAINT', + ($c_name ? $generator->quote($c_name) : () ), + 'CHECK' + ); + + + $def .= ' ('. $c->expression . ')'; + return $def; + } return undef; } diff --git a/t/17sqlfxml-producer.t b/t/17sqlfxml-producer.t index 7989e35d4..85042ce97 100644 --- a/t/17sqlfxml-producer.t +++ b/t/17sqlfxml-producer.t @@ -48,7 +48,7 @@ sub xml_equals my ($got, $expect, $msg) = (@_, "XML looks right"); $got =~ s/^ +//gm; $expect =~ s/^ +//gm; - eq_or_diff $got, $expect, $msg; + eq_or_diff $got, $expect, $msg, { context => 1 }; } # diff --git a/t/30sqlt-new-diff-mysql.t b/t/30sqlt-new-diff-mysql.t index 706c2752a..79df23f22 100644 --- a/t/30sqlt-new-diff-mysql.t +++ b/t/30sqlt-new-diff-mysql.t @@ -19,7 +19,7 @@ use_ok('SQL::Translator::Diff') or die "Cannot continue\n"; my $tr = SQL::Translator->new; -my ( $source_schema, $target_schema, $parsed_sql_schema ) = map { +my ( $source_schema, $target_schema ) = map { my $t = SQL::Translator->new; $t->parser( 'YAML' ) or die $tr->error; @@ -47,7 +47,7 @@ ok( @out, 'Got a list' ); my $out = join('', @out); -eq_or_diff($out, <<'## END OF DIFF', "Diff as expected"); +eq_or_diff($out, <<'## END OF DIFF', "Diff as expected", { context => 1 }); -- Convert schema 'create1.yml' to 'create2.yml':; BEGIN; @@ -64,7 +64,7 @@ ALTER TABLE old_name RENAME TO new_name; ALTER TABLE employee DROP FOREIGN KEY FK5302D47D93FE702E; -ALTER TABLE person DROP INDEX UC_age_name; +ALTER TABLE person DROP CONSTRAINT UC_age_name; ALTER TABLE person DROP INDEX u_name; @@ -109,7 +109,7 @@ $out = SQL::Translator::Diff::schema_diff($source_schema, 'MySQL', $target_schem producer_args => { quote_identifiers => 0 }, }); -eq_or_diff($out, <<'## END OF DIFF', "Diff as expected"); +eq_or_diff($out, <<'## END OF DIFF', "Diff as expected", { context => 1 }); -- Convert schema 'create1.yml' to 'create2.yml':; BEGIN; @@ -127,7 +127,7 @@ ALTER TABLE employee DROP COLUMN job_title; ALTER TABLE old_name RENAME TO new_name, ADD COLUMN new_field integer NULL; -ALTER TABLE person DROP INDEX UC_age_name, +ALTER TABLE person DROP CONSTRAINT UC_age_name, ADD COLUMN is_rock_star tinyint(4) NULL DEFAULT 1, CHANGE COLUMN person_id person_id integer(11) NOT NULL auto_increment, CHANGE COLUMN name name varchar(20) NOT NULL, @@ -151,7 +151,7 @@ COMMIT; # Test for sameness $out = SQL::Translator::Diff::schema_diff($source_schema, 'MySQL', $source_schema, 'MySQL' ); -eq_or_diff($out, <<'## END OF DIFF', "No differences found"); +eq_or_diff($out, <<'## END OF DIFF', "No differences found", { context => 1 }); -- Convert schema 'create1.yml' to 'create1.yml':; -- No differences found; @@ -179,7 +179,7 @@ eq_or_diff($out, <<'## END OF DIFF', "No differences found"); $field->data_type('integer'); $field->size(0); $out = SQL::Translator::Diff::schema_diff($schema, 'MySQL', $target_schema, 'MySQL', { producer_args => { quote_identifiers => 0 } } ); - eq_or_diff($out, <<'## END OF DIFF', "No differences found"); + eq_or_diff($out, <<'## END OF DIFF', "No differences found", { context => 1 }); -- Convert schema 'create.sql' to 'create2.yml':; BEGIN; @@ -193,10 +193,11 @@ CREATE TABLE added ( SET foreign_key_checks=1; ALTER TABLE employee DROP FOREIGN KEY FK5302D47D93FE702E, + DROP CONSTRAINT demo_constraint, DROP COLUMN job_title, ADD CONSTRAINT FK5302D47D93FE702E_diff FOREIGN KEY (employee_id) REFERENCES person (person_id); -ALTER TABLE person DROP INDEX UC_age_name, +ALTER TABLE person DROP CONSTRAINT UC_age_name, DROP INDEX u_name, ADD COLUMN is_rock_star tinyint(4) NULL DEFAULT 1, ADD COLUMN value double(8, 2) NULL DEFAULT 0.00, @@ -251,7 +252,7 @@ COMMIT; my $out = SQL::Translator::Diff::schema_diff($s1, 'MySQL', $s2, 'MySQL' ); - eq_or_diff($out, <<'## END OF DIFF', "Batch alter of constraints work for InnoDB"); + eq_or_diff($out, <<'## END OF DIFF', "Batch alter of constraints work for InnoDB", { context => 1 }); -- Convert schema 'Schema 1' to 'Schema 2':; BEGIN; @@ -302,7 +303,7 @@ COMMIT; ); my $out = SQL::Translator::Diff::schema_diff($s1, 'MySQL', $s2, 'MySQL' ); - eq_or_diff($out, <<'## END OF DIFF', "Alter/drop constraints works with rename table"); + eq_or_diff($out, <<'## END OF DIFF', "Alter/drop constraints works with rename table", { context => 1 }); -- Convert schema 'Schema 3' to 'Schema 4':; BEGIN; @@ -324,7 +325,7 @@ COMMIT; $out = SQL::Translator::Diff::schema_diff($s1, 'MySQL', $s2, 'MySQL', { producer_args => { quote_identifiers => 1 } } ); - eq_or_diff($out, <<'## END OF DIFF', "Quoting can be turned on"); + eq_or_diff($out, <<'## END OF DIFF', "Quoting can be turned on", { context => 1 }); -- Convert schema 'Schema 3' to 'Schema 4':; BEGIN; diff --git a/t/30sqlt-new-diff-pgsql.t b/t/30sqlt-new-diff-pgsql.t index 5bc782038..471dc8f43 100644 --- a/t/30sqlt-new-diff-pgsql.t +++ b/t/30sqlt-new-diff-pgsql.t @@ -19,7 +19,7 @@ use_ok('SQL::Translator::Diff') or die "Cannot continue\n"; my $tr = SQL::Translator->new; -my ( $source_schema, $target_schema, $parsed_sql_schema ) = map { +my ( $source_schema, $target_schema ) = map { my $t = SQL::Translator->new; $t->parser( 'YAML' ) or die $tr->error; diff --git a/t/data/mysql/create.sql b/t/data/mysql/create.sql index 642d9a233..e13eab026 100644 --- a/t/data/mysql/create.sql +++ b/t/data/mysql/create.sql @@ -4,18 +4,19 @@ create table person ( age integer, weight double(11,2), iq tinyint default '0', - description text, + description text default `name`, UNIQUE KEY UC_age_name (age) ) ENGINE=MyISAM; create unique index u_name on person (name); create table employee ( - position varchar(50), - employee_id integer, + position varchar(50), + employee_id integer, job_title varchar(255), - CONSTRAINT FK5302D47D93FE702E FOREIGN KEY (employee_id) REFERENCES person (person_id), - PRIMARY KEY (position, employee_id) USING BTREE + CONSTRAINT FK5302D47D93FE702E FOREIGN KEY (employee_id) REFERENCES person (person_id), + CONSTRAINT `demo_constraint` CHECK (`employee_id` > 0 and `employee_id` IS NOT NULL), + PRIMARY KEY (position, employee_id) USING BTREE ) ENGINE=InnoDB; create table deleted ( diff --git a/t/data/mysql/create2.sql b/t/data/mysql/create2.sql index 54cf4bb68..037b182a0 100644 --- a/t/data/mysql/create2.sql +++ b/t/data/mysql/create2.sql @@ -16,6 +16,7 @@ create table employee ( position varchar(50), employee_id INTEGER, CONSTRAINT FK5302D47D93FE702E_diff FOREIGN KEY (employee_id) REFERENCES person (person_id), + CONSTRAINT `demo_constraint` CHECK (`employee_id` > 0 and `employee_id` IS NOT NULL and `employee_id` not in (0)), PRIMARY KEY (employee_id, position) ) ENGINE=InnoDB; diff --git a/t/data/sqlite/named.sql b/t/data/sqlite/named.sql index 36546906b..a48686f25 100644 --- a/t/data/sqlite/named.sql +++ b/t/data/sqlite/named.sql @@ -8,6 +8,6 @@ create table pet ( constraint fk_person_id_3 references person(person_id) on update NO ACTION, "name" varchar(30), "age" int, - constraint age_under_100 check ( age < 100 ), + constraint age_under_100 check ( age < 100 and age not in (101, 102) ), constraint pk_pet primary key (pet_id, person_id) );