From 775f92b683956d6bf2ba373bb6004f6b8d17655e Mon Sep 17 00:00:00 2001 From: reneeb Date: Mon, 6 Jul 2020 10:42:17 +0200 Subject: [PATCH] improve parsing of CREATE VIEW statements with SQL::Translator::Parser::MySQL Currently the module supports only simple views like 'CREATE VIEW view1 AS SELECT ... FROM table', but not more complex statments that may contain 'JOIN's. Furthermore the used tables aren't reported. This commit fixes those issues. --- lib/SQL/Translator/Parser/MySQL.pm | 48 ++++++++++++++++++++++++++---- t/02mysql-parser.t | 29 ++++++++++++++++++ 2 files changed, 72 insertions(+), 5 deletions(-) diff --git a/lib/SQL/Translator/Parser/MySQL.pm b/lib/SQL/Translator/Parser/MySQL.pm index 5df48ed61..0324df97d 100644 --- a/lib/SQL/Translator/Parser/MySQL.pm +++ b/lib/SQL/Translator/Parser/MySQL.pm @@ -353,10 +353,25 @@ create : CREATE or_replace(?) create_view_option(s?) /view/i NAME /as/i view_sel ' from ', join(', ', map { - sprintf('%s%s', - $_->{'name'}, - $_->{'alias'} ? ' as ' . $_->{'alias'} : '' - ) + $_->{'join'} ? + () : + sprintf('%s%s', + $_->{'name'}, + $_->{'alias'} ? ' as ' . $_->{'alias'} : '' + ) + } + @{ $select_sql->{'from'}{'tables'} || [] } + ), + join(' ', + map { + $_->{'join'} ? + sprintf('%s%s%s ON %s', + $_->{'join'}, + $_->{'name'}, + $_->{'alias'} ? ' as ' . $_->{'alias'} : '', + $_->{'on'} + ) : + (); } @{ $select_sql->{'from'}{'tables'} || [] } ), @@ -374,6 +389,7 @@ create : CREATE or_replace(?) create_view_option(s?) /view/i NAME /as/i view_sel $views{ $view_name }{'sql'} = $sql; $views{ $view_name }{'options'} = $options; $views{ $view_name }{'select'} = $item{'view_select_statement'}; + $views{ $view_name }{'from'}{'tables'} = $select_sql->{'from'}{'tables'}; } create_view_option : view_algorithm | view_sql_security | view_definer @@ -426,10 +442,32 @@ view_table_def : not_delimiter my $where = $1 if $clause =~ s/\bwhere \s+ (.*)//ixs; $clause =~ s/[)]\s*$//; + my $joins = ''; + $joins = $1 if $clause =~ s/ + \b((?:(?:left|right)\s+)? + (?:(?:inner|outer)\s+) + join .*)\z + //ixs; + my @tables; for my $tbl ( split( /\s*,\s*/, $clause ) ) { my ( $name, $alias ) = split /\s+as\s+/i, $tbl; - push @tables, { name => $name, alias => $alias || '' }; + push @tables, { name => $name, alias => $alias || '', join => 0 }; + } + + my @all_joins = split / + \b((?:(?:left|right)\s+)? + (?:(?:inner|outer)\s+) + join) + /ixsg, $joins; + + shift @all_joins if @all_joins; + + while ( @all_joins ) { + my $join = shift @all_joins; + my ( $table, $on ) = split /\s+on\s+/i, shift @all_joins; + my ( $name, $alias ) = split /\s+as\s+/i, $table; + push @tables, { name => $name, alias => $alias || '', join => $join, on => $on }; } $return = { diff --git a/t/02mysql-parser.t b/t/02mysql-parser.t index d521b9d6e..5257817da 100644 --- a/t/02mysql-parser.t +++ b/t/02mysql-parser.t @@ -959,4 +959,33 @@ ok ($@, 'Exception thrown on invalid version string'); ok (my $schema = $tr->schema, 'got schema'); } +{ + # test view definitions with join + my $view = q~ + CREATE VIEW `view1` AS + SELECT + table1.cidr, col2 + FROM + table1 + INNER JOIN + table2 + ON table1.cidr = table2.cidr ; + ~; + + my $tr = SQL::Translator->new; + my $sub = $tr->parser( 'SQL::Translator::Parser::MySQL' ); + $sub->( $tr, $view ); + + my $schema = $tr->schema; + + my @views = $schema->get_views; + is( scalar @views, 1, 'Right number of views (1)' ); + + my ($view_obj) = $views[0]; + is( $view_obj->name, 'view1' ); + my $tables = $view_obj->tables; + is_deeply( $tables, [qw/table1 table2/] ); + is( $view_obj->sql, "CREATE view1 as select table1.cidr, col2 from table1\n INNER JOIN\n table2 ON table1.cidr = table2.cidr " ); +} + done_testing;