From 707abe2f69bc97cab364bca6ebbf588a698feb5d Mon Sep 17 00:00:00 2001 From: Adam Herzog Date: Sun, 2 Apr 2017 16:12:07 -0400 Subject: [PATCH 1/4] MySQL Parser understands VIEWs with a field list. Updates the MySQL parser to properly parse CREATE VIEW statements that contain a field list after the view name. This allows the parser to understand statements created by the MySQL producer. Prior to this change, this statement would be parsed properly: CREATE VIEW view_foo AS SELECT id, name FROM thing; But this one would not: CREATE VIEW view_foo (id, name) AS SELECT id, name FROM thing; --- lib/SQL/Translator/Parser/MySQL.pm | 2 +- t/02mysql-parser.t | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/lib/SQL/Translator/Parser/MySQL.pm b/lib/SQL/Translator/Parser/MySQL.pm index c915af540..d2c52caf5 100644 --- a/lib/SQL/Translator/Parser/MySQL.pm +++ b/lib/SQL/Translator/Parser/MySQL.pm @@ -326,7 +326,7 @@ create : CREATE PROCEDURE NAME not_delimiter "$delimiter" PROCEDURE : /procedure/i | /function/i -create : CREATE or_replace(?) create_view_option(s?) /view/i NAME /as/i view_select_statement "$delimiter" +create : CREATE or_replace(?) create_view_option(s?) /view/i NAME parens_field_list(?) /as/i view_select_statement "$delimiter" { @table_comments = (); my $view_name = $item{'NAME'}; diff --git a/t/02mysql-parser.t b/t/02mysql-parser.t index d521b9d6e..b921a5be8 100644 --- a/t/02mysql-parser.t +++ b/t/02mysql-parser.t @@ -502,6 +502,19 @@ BEGIN { is( join(',', $t2c2->reference_fields), 'id', 'To field "id"' ); } +# Tests for CREATE VIEW statements that contain a column list +# after the view name +{ + my $tr = SQL::Translator->new(); + my $data = parse($tr, + q[ + CREATE + VIEW view_foo (id, name) AS + SELECT id, name FROM thing; + ] + ) or die $tr->error; +} + # cch Tests for: # comments like: /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; # char fields with character set and collate qualifiers From 3d090a57dade84c203b42abfec50dc57b51ed26d Mon Sep 17 00:00:00 2001 From: Adam Herzog Date: Mon, 10 Apr 2017 11:35:12 -0400 Subject: [PATCH 2/4] Include 'view' keyword in MySQL Parser generated SQL. --- lib/SQL/Translator/Parser/MySQL.pm | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/SQL/Translator/Parser/MySQL.pm b/lib/SQL/Translator/Parser/MySQL.pm index d2c52caf5..a10b96142 100644 --- a/lib/SQL/Translator/Parser/MySQL.pm +++ b/lib/SQL/Translator/Parser/MySQL.pm @@ -339,6 +339,7 @@ create : CREATE or_replace(?) create_view_option(s?) /view/i NAME parens_field_l $item{'CREATE'}, $item{'or_replace(?)'}, $options, + 'view', $view_name, 'as select', join(', ', From 8bdf3bfc4c8c44685d1189a4acfd10732136de33 Mon Sep 17 00:00:00 2001 From: Adam Herzog Date: Mon, 10 Apr 2017 11:35:32 -0400 Subject: [PATCH 3/4] Improve MySQL view parsing of field list, w/tests. --- lib/SQL/Translator/Parser/MySQL.pm | 7 ++++ t/02mysql-parser.t | 56 +++++++++++++++++++++++++++--- 2 files changed, 58 insertions(+), 5 deletions(-) diff --git a/lib/SQL/Translator/Parser/MySQL.pm b/lib/SQL/Translator/Parser/MySQL.pm index a10b96142..1c4745235 100644 --- a/lib/SQL/Translator/Parser/MySQL.pm +++ b/lib/SQL/Translator/Parser/MySQL.pm @@ -332,6 +332,13 @@ create : CREATE or_replace(?) create_view_option(s?) /view/i NAME parens_field_l my $view_name = $item{'NAME'}; my $select_sql = $item{'view_select_statement'}; my $options = $item{'create_view_option(s?)'}; + my $field_list = $item{'parens_field_list(?)'}; + + # Map fields as aliases on the select columns + my @fields = ( $field_list->[0] ) ? @{ $field_list->[0] } : (); + map { $select_sql->{'columns'}->[$_]->{'alias'} = $fields[$_] } + ( 0 .. $#fields ) + if (@fields); my $sql = join(q{ }, grep { defined and length } diff --git a/t/02mysql-parser.t b/t/02mysql-parser.t index b921a5be8..13febfcf4 100644 --- a/t/02mysql-parser.t +++ b/t/02mysql-parser.t @@ -502,17 +502,63 @@ BEGIN { is( join(',', $t2c2->reference_fields), 'id', 'To field "id"' ); } -# Tests for CREATE VIEW statements that contain a column list -# after the view name +# Tests CREATE VIEW statements containing field lists and/or aliases { - my $tr = SQL::Translator->new(); - my $data = parse($tr, + my $tr = SQL::Translator->new(); + my $data = parse( + $tr, q[ CREATE - VIEW view_foo (id, name) AS + VIEW view_foo (a, b) AS SELECT id, name FROM thing; + + CREATE + VIEW view_bar AS + SELECT id AS c, name AS d FROM thing; + + CREATE + VIEW view_baz (e, f) AS + SELECT id AS g, name AS h FROM thing; ] ) or die $tr->error; + + my $schema = $tr->schema; + my @views = $schema->get_views; + is( scalar @views, 3, 'Right number of views (3)' ); + my ( $view1, $view2, $view3 ) = @views; + + is( $view1->name, 'view_foo', 'Found "view_foo" view' ); + is( join( ',', $view1->fields ), + join( ',', qw[ a b ] ), + 'View 1 has correct fields' + ); + like( + $view1->sql, + qr/create view view_foo as select id as a, name as b\s+from\s+thing/i, + 'View 1 has correct sql' + ); + + is( $view2->name, 'view_bar', 'Found "view_bar" view' ); + is( join( ',', $view2->fields ), + join( ',', qw[ c d ] ), + 'View 2 has correct fields' + ); + like( + $view2->sql, + qr/create view view_bar as select id as c, name as d\s+from\s+thing/i, + 'View 2 has correct sql' + ); + + is( $view3->name, 'view_baz', 'Found "view_baz" view' ); + is( join( ',', $view3->fields ), + join( ',', qw[ e f ] ), + 'View 3 has correct fields' + ); + like( + $view3->sql, + qr/create view view_baz as select id as e, name as f\s+from\s+thing/i, + 'View 3 has correct sql' + ); } # cch Tests for: From 995392669dc0f4e3dc52c89954714c62f145b05d Mon Sep 17 00:00:00 2001 From: Adam Herzog Date: Mon, 10 Apr 2017 14:06:31 -0400 Subject: [PATCH 4/4] Simplify setting of column aliases from field list. --- lib/SQL/Translator/Parser/MySQL.pm | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/lib/SQL/Translator/Parser/MySQL.pm b/lib/SQL/Translator/Parser/MySQL.pm index 1c4745235..0bece231b 100644 --- a/lib/SQL/Translator/Parser/MySQL.pm +++ b/lib/SQL/Translator/Parser/MySQL.pm @@ -332,13 +332,11 @@ create : CREATE or_replace(?) create_view_option(s?) /view/i NAME parens_field_l my $view_name = $item{'NAME'}; my $select_sql = $item{'view_select_statement'}; my $options = $item{'create_view_option(s?)'}; - my $field_list = $item{'parens_field_list(?)'}; - # Map fields as aliases on the select columns - my @fields = ( $field_list->[0] ) ? @{ $field_list->[0] } : (); - map { $select_sql->{'columns'}->[$_]->{'alias'} = $fields[$_] } - ( 0 .. $#fields ) - if (@fields); + # Use the field list as column aliases, if specified + my @fields = @{$item{'parens_field_list(?)'}[0] || []}; + $select_sql->{columns}->[$_]->{alias} = $fields[$_] + for 0..$#fields; my $sql = join(q{ }, grep { defined and length }