From 2f5232251a9ce651e4dd3c80ce6671e8f4631978 Mon Sep 17 00:00:00 2001 From: Marc Mims Date: Thu, 21 May 2015 16:57:06 -0700 Subject: [PATCH 1/2] Don't create a superfluous index for FK that is PK If the primary key is also a foreign key, there's no need to create an index for it, because the primary key constraint will suffice. --- lib/SQL/Translator/Producer/MySQL.pm | 8 +++- t/38-mysql-producer.t | 57 +++++++++++++++++++++++++++- 2 files changed, 63 insertions(+), 2 deletions(-) diff --git a/lib/SQL/Translator/Producer/MySQL.pm b/lib/SQL/Translator/Producer/MySQL.pm index 904b294c3..85cd0da70 100644 --- a/lib/SQL/Translator/Producer/MySQL.pm +++ b/lib/SQL/Translator/Producer/MySQL.pm @@ -457,11 +457,17 @@ sub create_table # my @constraint_defs; my @constraints = $table->get_constraints; + + # Get the primary key, if there is one. No need to create an index for an + # FK that is also the PK. It may be a multi-field key, so generate a + # suitable string for comparison. + my $pk = join "\0", map $_->fields, grep $_->type eq PRIMARY_KEY, @constraints; for my $c ( @constraints ) { my $constr = create_constraint($c, $options); push @constraint_defs, $constr if($constr); - unless ( $indexed_fields{ ($c->fields())[0] } || $c->type ne FOREIGN_KEY ) { + unless ( $indexed_fields{ ($c->fields())[0] } || $c->type ne FOREIGN_KEY + || ($c->fields)[0] eq $pk ) { push @index_defs, "INDEX (" . $generator->quote(($c->fields())[0]) . ")"; $indexed_fields{ ($c->fields())[0] } = 1; } diff --git a/t/38-mysql-producer.t b/t/38-mysql-producer.t index 446186bdf..af011ca3b 100644 --- a/t/38-mysql-producer.t +++ b/t/38-mysql-producer.t @@ -19,7 +19,7 @@ use FindBin qw/$Bin/; #============================================================================= BEGIN { - maybe_plan(73, + maybe_plan(75, 'YAML', 'SQL::Translator::Producer::MySQL', 'Test::Differences', @@ -800,3 +800,58 @@ EOV is(SQL::Translator::Producer::MySQL::alter_drop_constraint($constraint,$options), 'ALTER TABLE `table` DROP PRIMARY KEY','valid drop primary key'); } + +{ # do not create an extra index for a FK that is also the PK + my $sqlt; + $sqlt = SQL::Translator->new( + show_warnings => 1, + no_comments => 1, + from => "YAML", + to => "MySQL", + quote_table_names => 1, + quote_field_names => 1 + ); + + my $out = $sqlt->translate(\<<'EOT') or die "Translate error:".$sqlt->error; +--- +schema: + tables: + thing: + name: thing + extra: + order: 1 + fields: + id: + name: id + data_type: int + is_primary_key: 1 + order: 1 + is_foreign_key: 0 + constraints: + - type: PRIMARY_KEY + fields: + - id + thing2: + name: thing2 + extra: + order: 2 + fields: + thing_id: + name: thing_id + data_type: int + is_primary_key: 1 + order: 1 + is_foreign_key: 1 + constraints: + - type: PRIMARY_KEY + fields: + - thing_id + - reference_table: thing + type: FOREIGN_KEY + fields: thing_id + name: fk_thing +EOT + + like $out, qr/PRIMARY KEY \(`thing_id`\)/, 'created primary key'; + unlike $out, qr/INDEX \(`thing_id`\)/, 'no extra index'; +} From 16c8fb94177d99191e4cff18cd4701d97689f3bd Mon Sep 17 00:00:00 2001 From: Marc Mims Date: Thu, 2 Jul 2015 13:47:36 -0700 Subject: [PATCH 2/2] Handle multi-column FK/PK constraints --- lib/SQL/Translator/Producer/MySQL.pm | 21 ++++++++------- t/38-mysql-producer.t | 38 ++++++++++++++++++++-------- 2 files changed, 40 insertions(+), 19 deletions(-) diff --git a/lib/SQL/Translator/Producer/MySQL.pm b/lib/SQL/Translator/Producer/MySQL.pm index 85cd0da70..7aaeb1a74 100644 --- a/lib/SQL/Translator/Producer/MySQL.pm +++ b/lib/SQL/Translator/Producer/MySQL.pm @@ -449,7 +449,8 @@ sub create_table my %indexed_fields; for my $index ( $table->get_indices ) { push @index_defs, create_index($index, $options); - $indexed_fields{ $_ } = 1 for $index->fields; + $indexed_fields{ join "\0", $index->fields } = 1; + $indexed_fields{ ($index->fields)[0] } = 1; } # @@ -458,18 +459,20 @@ sub create_table my @constraint_defs; my @constraints = $table->get_constraints; - # Get the primary key, if there is one. No need to create an index for an - # FK that is also the PK. It may be a multi-field key, so generate a - # suitable string for comparison. - my $pk = join "\0", map $_->fields, grep $_->type eq PRIMARY_KEY, @constraints; + for my $pk ( grep $_->type eq PRIMARY_KEY, @constraints ) { + $indexed_fields{ join "\0", $pk->fields } = 1; + $indexed_fields{ ($pk->fields)[0] } = 1; + } + + for my $c ( @constraints ) { my $constr = create_constraint($c, $options); push @constraint_defs, $constr if($constr); - unless ( $indexed_fields{ ($c->fields())[0] } || $c->type ne FOREIGN_KEY - || ($c->fields)[0] eq $pk ) { - push @index_defs, "INDEX (" . $generator->quote(($c->fields())[0]) . ")"; - $indexed_fields{ ($c->fields())[0] } = 1; + unless ( $indexed_fields{ join("\0", $c->fields) } || $c->type ne FOREIGN_KEY ) { + push @index_defs, "INDEX (" . join(', ' => map $generator->quote($_), $c->fields) . ")"; + $indexed_fields{ join("\0", $c->fields) } = 1; + $indexed_fields{ ($c->fields)[0] } = 1; } } diff --git a/t/38-mysql-producer.t b/t/38-mysql-producer.t index af011ca3b..59e775843 100644 --- a/t/38-mysql-producer.t +++ b/t/38-mysql-producer.t @@ -19,7 +19,7 @@ use FindBin qw/$Bin/; #============================================================================= BEGIN { - maybe_plan(75, + maybe_plan(76, 'YAML', 'SQL::Translator::Producer::MySQL', 'Test::Differences', @@ -821,37 +821,55 @@ schema: extra: order: 1 fields: - id: - name: id + id1: + name: id1 data_type: int is_primary_key: 1 order: 1 is_foreign_key: 0 + id2: + name: id2 + data_type: int + is_primary_key: 1 + order: 2 + is_foreign_key: 0 constraints: - type: PRIMARY_KEY fields: - - id + - id1 + - id2 thing2: name: thing2 extra: order: 2 fields: - thing_id: - name: thing_id + thing2_id1: + name: thing2_id1 data_type: int is_primary_key: 1 order: 1 is_foreign_key: 1 + thing2_id2: + name: thing2_id2 + data_type: int + is_primary_key: 1 + order: 2 + is_foreign_key: 1 constraints: - type: PRIMARY_KEY fields: - - thing_id + - thing2_id1 + - thing2_id2 - reference_table: thing type: FOREIGN_KEY - fields: thing_id + fields: + - thing2_id1 + - thing2_id2 name: fk_thing EOT - like $out, qr/PRIMARY KEY \(`thing_id`\)/, 'created primary key'; - unlike $out, qr/INDEX \(`thing_id`\)/, 'no extra index'; + note $out; + like $out, qr/PRIMARY KEY \(`thing2_id1`, `thing2_id2`\)/, 'created primary key'; + unlike $out, qr/INDEX \(`thing2_id1`, `thing2_id2`\)/, 'no extra index'; + unlike $out, qr/INDEX \(`thing2_id1`\)/, 'no single column index'; }