Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SQLite and MySQL parser to understand CHECK with parens #123

Merged
merged 7 commits into from Apr 6, 2020
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
24 changes: 24 additions & 0 deletions lib/SQL/Translator/Parser/MySQL.pm
Expand Up @@ -700,8 +700,31 @@ primary_key : /primary/i /key/i { 1 }
constraint : primary_key_def
| unique_key_def
| foreign_key_def
| check_def
| <error>

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 = {
Expand Down Expand Up @@ -1017,6 +1040,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'} || '',
Expand Down
21 changes: 19 additions & 2 deletions lib/SQL/Translator/Producer/MySQL.pm
Expand Up @@ -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);
Expand All @@ -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(
Expand All @@ -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.
#
Expand Down Expand Up @@ -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;
}
Expand Down
2 changes: 1 addition & 1 deletion t/17sqlfxml-producer.t
Expand Up @@ -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 };
}

#
Expand Down
23 changes: 12 additions & 11 deletions t/30sqlt-new-diff-mysql.t
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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;

Expand Down Expand Up @@ -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;
Expand All @@ -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,
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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,
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion t/30sqlt-new-diff-pgsql.t
Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions t/data/mysql/create.sql
Expand Up @@ -15,6 +15,7 @@ create table employee (
employee_id integer,
job_title varchar(255),
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;

Expand Down
1 change: 1 addition & 0 deletions t/data/mysql/create2.sql
Expand Up @@ -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;

Expand Down