From d3ad8c84c078695155ceb3560b20b0d8e4e226f9 Mon Sep 17 00:00:00 2001 From: Daniel Nichter Date: Sat, 24 Mar 2012 12:47:08 -0600 Subject: [PATCH] Do not ever create --new-table. Rewrite basics.t. Add more debug statements. --- bin/pt-online-schema-change | 48 +- t/pt-online-schema-change/basics.t | 450 +++++++++++------- .../{small_table.sql => basic_no_fks.sql} | 23 +- ...k_tables_schema.sql => basic_with_fks.sql} | 31 +- 4 files changed, 344 insertions(+), 208 deletions(-) rename t/pt-online-schema-change/samples/{small_table.sql => basic_no_fks.sql} (55%) rename t/pt-online-schema-change/samples/{fk_tables_schema.sql => basic_with_fks.sql} (63%) diff --git a/bin/pt-online-schema-change b/bin/pt-online-schema-change index 1d9f1a00..07987266 100755 --- a/bin/pt-online-schema-change +++ b/bin/pt-online-schema-change @@ -5208,15 +5208,15 @@ sub main { print "Starting a dry run. $orig_tbl->{name} will not be altered. " . "Specify --execute instead of --dry-run to alter the table.\n"; } - elsif ( !$o->get('execute') ) { + elsif ( $o->get('execute') ) { + print "Altering $orig_tbl->{name}...\n"; + } + else { print "Exiting without altering $orig_tbl->{name} because neither " . "--dry-run nor --execute was specified. Please read the tool's " . "documentation carefully before using this tool.\n"; return $exit_status; } - else { - print "Altering $orig_tbl->{name}...\n"; - } # ######################################################################## # Check and create PID file if user specified --pid. @@ -5241,7 +5241,15 @@ sub main { db => $db, tbl => $tbl, ); - if ( !$new_table_exists ) { + if ( $new_table_exists ) { + # Do not create the new table if it already exists in case the user + # does something bad like --new-table wrong.table because then we'll + # modify the wrong table and really break stuff. + die "The --new-table $new_table already exists. Please specify " + . "a new table name that does not yet exist.\n"; + } + else { + # --new-table does not exist. Create it? if ( $o->get('create-new-table') ) { my $sql = "CREATE TABLE $new_table LIKE $orig_tbl->{name}"; PTDEBUG && _d($sql); @@ -5711,6 +5719,7 @@ sub main { . "by executing: $drop_new_table_sql\n"; } } + PTDEBUG && _d('Old table:', Dumper($old_tbl)); # ##################################################################### # Update foreign key constraints if there are child tables. @@ -5983,7 +5992,9 @@ sub find_child_tables { die "I need a $arg argument" unless $args{$arg}; } my ($tbl, $cxn, $q) = @args{@required_args}; - + + PTDEBUG && _d('Finding child tables'); + my $sql = "SELECT table_name " . "FROM information_schema.key_column_usage " . "WHERE constraint_schema='$tbl->{db}' " @@ -5995,8 +6006,8 @@ sub find_child_tables { return; } - PTDEBUG && _d("Child tables:", Dumper($child_tables)); my @child_tables = map { $_->[0] } @$child_tables; + PTDEBUG && _d("Child tables:", @child_tables); return \@child_tables; } @@ -6013,6 +6024,8 @@ sub rebuild_constraints { my $exit_status = 0; my $constraint = qr/^\s+(CONSTRAINT.+?REFERENCES `$old_tbl->{tbl}`.+)$/m; + PTDEBUG && _d('Rebuilding fk constraint:', $constraint); + if ( $o->get('dry-run') ) { print "Not rebuilding foreign key constraints because this is a dry run.\n"; } @@ -6043,19 +6056,26 @@ sub rebuild_constraints { } foreach my $constraint ( @constraints ) { - my ($fk_symbol) = $constraint =~ m/CONSTRAINT\s+(\S+)/; + PTDEBUG && _d('Rewriting fk constraint:', $constraint); + my ($fk) = $constraint =~ m/CONSTRAINT\s+(\S+)/; # Drop the reference to the old table/renamed orig table. - $sql = "ALTER TABLE $child_table DROP FOREIGN KEY $fk_symbol"; - print $sql, "\n" if $o->get('print'); - $cxn->dbh()->do($sql) if $o->get('execute'); + $sql = "ALTER TABLE $child_table DROP FOREIGN KEY $fk"; + print $sql, "\n" if $o->get('print'); + if ( $o->get('execute') ) { + PTDEBUG && _d($sql); + $cxn->dbh()->do($sql); + } # Make the child reference the new table, i.e. the table name it # originally referenced instead of the old/renamed orig table. - $constraint =~ s/REFERENCES `$old_tbl->{tbl}`/REFERENCES `$orig_tbl->{tbl}`/o; + $constraint =~ s/REFERENCES `$old_tbl->{tbl}`/REFERENCES `$orig_tbl->{tbl}`/; $sql = "ALTER TABLE $child_table ADD $constraint"; - print $sql, "\n" if $o->get('print'); - $cxn->dbh()->do($sql) if $o->get('execute'); + print $sql, "\n" if $o->get('print'); + if ( $o->get('execute') ) { + PTDEBUG && _d($sql); + $cxn->dbh()->do($sql); + } } } diff --git a/t/pt-online-schema-change/basics.t b/t/pt-online-schema-change/basics.t index 18eccf15..865eea9d 100644 --- a/t/pt-online-schema-change/basics.t +++ b/t/pt-online-schema-change/basics.t @@ -16,150 +16,227 @@ use Sandbox; require "$trunk/bin/pt-online-schema-change"; use Data::Dumper; +$Data::Dumper::Indent = 1; +$Data::Dumper::Sortkeys = 1; +$Data::Dumper::Quotekeys = 0; -my $dp = new DSNParser(opts=>$dsn_opts); -my $sb = new Sandbox(basedir => '/tmp', DSNParser => $dp); -my $dbh = $sb->get_dbh_for('master'); +my $dp = new DSNParser(opts=>$dsn_opts); +my $sb = new Sandbox(basedir => '/tmp', DSNParser => $dp); +my $master_dbh = $sb->get_dbh_for('master'); +my $slave_dbh = $sb->get_dbh_for('slave1'); -if ( !$dbh ) { +if ( !$master_dbh ) { plan skip_all => 'Cannot connect to sandbox master'; } else { - plan tests => 23; + plan tests => 38; } -my $output = ""; -my $cnf = '/tmp/12345/my.sandbox.cnf'; -my @args = ('-F', $cnf, '--execute'); -my $exit = 0; +my $q = new Quoter(); +my $tp = new TableParser(Quoter => $q); +my @args = qw(--lock-wait-timeout 3); +my $output = ""; +my $dsn = "h=127.1,P=12345,u=msandbox,p=msandbox"; +my $exit = 0; +my $sample = "t/pt-online-schema-change/samples"; my $rows; -$sb->load_file('master', "t/pt-online-schema-change/samples/small_table.sql"); -$dbh->do('use mkosc'); - # ############################################################################# # Tool shouldn't run without --execute (bug 933232). # ############################################################################# + +$sb->load_file('master', "$sample/basic_no_fks.sql"); +PerconaTest::wait_for_table($slave_dbh, "pt_osc.t", "id=20"); + +# --new-table really ensures the tool exists before doing stuff because +# setting up the new table is the first thing the tool does and this would +# cause an error because mysql.user already exists. To prove this, add +# --dry-run and the test will fail because the code doesn't exit early. $output = output( - sub { pt_online_schema_change::main('h=127.1,P=12345,u=msandbox,p=msandbox,D=mkosc,t=a') }, + sub { $exit = pt_online_schema_change::main(@args, "$dsn,t=pt_osc.t", + qw(--new-table mysql.user)) } ); like( $output, - qr/you did not specify --execute/, - "Doesn't run without --execute" -); - -# ############################################################################# -# --check-tables-and-exit -# ############################################################################# -eval { - $exit = pt_online_schema_change::main(@args, - 'D=mkosc,t=a', qw(--check-tables-and-exit --quiet)) -}; - -is( - $EVAL_ERROR, - "", - "--check-tables-and-exit" + qr/neither --dry-run nor --execute was specified/, + "Doesn't run without --execute (bug 933232)" ); is( $exit, 0, - "Exit status 0" + "Exit 0" ); # ############################################################################# -# --cleanup-and-exit -# ############################################################################# -eval { - $exit = pt_online_schema_change::main(@args, - 'D=mkosc,t=a', qw(--cleanup-and-exit --quiet)) -}; - -is( - $EVAL_ERROR, - "", - "--cleanup-and-exit", -); - -is( - $exit, - 0, - "Exit status 0" -); - -# ############################################################################# -# The most basic: copy, alter and rename a small table that's not even active. +# A helper sub to do the heavy lifting for us. # ############################################################################# -output( - sub { $exit = pt_online_schema_change::main(@args, - 'D=mkosc,t=a', qw(--alter ENGINE=InnoDB)) }, -); +sub test_alter_table { + my (%args) = @_; + return if $args{skip}; -$rows = $dbh->selectall_hashref('show table status from mkosc', 'name'); -is( - $rows->{a}->{engine}, - 'InnoDB', - "New table ENGINE=InnoDB" -); + my @required_args = qw(name table test_type cmds); + foreach my $arg ( @required_args ) { + die "I need a $arg argument" unless $args{$arg}; + } + my ($name, $table, $test_type, $cmds) = @args{@required_args}; -is( - $rows->{__old_a}->{engine}, - 'MyISAM', - "Kept old table, ENGINE=MyISAM" -); + my ($db, $tbl) = $q->split_unquote($table); + my $pk_col = $args{pk_col} || 'id'; -my $org_rows = $dbh->selectall_arrayref('select * from mkosc.__old_a order by i'); -my $new_rows = $dbh->selectall_arrayref('select * from mkosc.a order by i'); -is_deeply( - $new_rows, - $org_rows, - "New tables rows identical to old table rows" -); + if ( my $file = $args{file} ) { + $sb->load_file('master', "$sample/$file"); + if ( my $wait = $args{wait} ) { + PerconaTest::wait_for_table($slave_dbh, @$wait); + } + else { + PerconaTest::wait_for_table($slave_dbh, $table, "`$pk_col`=$args{max_id}"); + } + $master_dbh->do("USE `$db`"); + $slave_dbh->do("USE `$db`"); + } -is( - $exit, - 0, - "Exit status 0" -); + my $ddl = $tp->get_create_table($master_dbh, $db, $tbl); + my $tbl_struct = $tp->parse($ddl); + + my $cols = '*'; + if ( $test_type eq 'drop_col' && !grep { $_ eq '--dry-run' } @$cmds ) { + # Don't select the column being dropped. + my $col = $args{drop_col}; + die "I need a drop_col argument" unless $col; + $cols = join(', ', grep { $_ ne $col } @{$tbl_struct->{cols}}); + } + my $orig_rows = $master_dbh->selectall_arrayref( + "SELECT $cols FROM $table ORDER BY `$pk_col`"); + + my $orig_tbls = $master_dbh->selectall_arrayref( + "SHOW TABLES FROM `$db`"); + + my @orig_fks; + if ( $args{check_fks} ) { + foreach my $tbl ( @$orig_tbls ) { + my $fks = $tp->get_fks( + $tp->get_create_table($master_dbh, $db, $tbl->[0])); + push @orig_fks, $fks; + } + } + + $output = output( + sub { $exit = pt_online_schema_change::main( + @args, + "$dsn,D=$db,t=$tbl", + @$cmds, + )}, + ); + + is( + $exit, + 0, + "$name exit 0" + ); + + # There should be no new or missing tables. + my $new_tbls = $master_dbh->selectall_arrayref("SHOW TABLES FROM `$db`"); + is_deeply( + $new_tbls, + $orig_tbls, + "$name tables" + ); + + # Rows in the original and new table should be identical. + my $new_rows = $master_dbh->selectall_arrayref("SELECT * FROM $table ORDER BY `$pk_col`"); + is_deeply( + $new_rows, + $orig_rows, + "$name rows" + ); + + # Check if the ALTER was actually done. + if ( $test_type eq 'drop_col' ) { + my $col = $q->quote($args{drop_col}); + my $ddl = $tp->get_create_table($master_dbh, $db, $tbl); + if ( grep { $_ eq '--dry-run' } @$cmds ) { + like( + $ddl, + qr/^\s+$col\s+/m, + "$name ALTER DROP COLUMN=$args{drop_col} (dry run)" + ); + } + else { + unlike( + $ddl, + qr/^\s+$col\s+/m, + "$name ALTER DROP COLUMN=$args{drop_col}" + ); + } + } + elsif ( $test_type eq 'add_col' ) { + } + elsif ( $test_type eq 'new_engine' ) { + my $new_engine = lc($args{new_engine}); + die "I need a new_engine argument" unless $new_engine; + my $rows = $master_dbh->selectall_hashref( + "SHOW TABLE STATUS FROM `$db`", "name"); + is( + lc($rows->{$tbl}->{engine}), + $new_engine, + "$name ALTER ENGINE=$args{new_engine}" + ); + + } + + if ( $args{check_fks} ) { + my @new_fks; + foreach my $tbl ( @$orig_tbls ) { + my $fks = $tp->get_fks( + $tp->get_create_table($master_dbh, $db, $tbl->[0])); + push @new_fks, $fks; + } + is_deeply( + \@new_fks, + \@orig_fks, + "$name FK constraints" + ); + } + + return; +} # ############################################################################# -# No --alter and --drop-old-table. +# The most basic: alter a small table with no fks that's not active. # ############################################################################# -$dbh->do('drop table if exists mkosc.__old_a'); # from previous run -$sb->load_file('master', "t/pt-online-schema-change/samples/small_table.sql"); -output( - sub { $exit = pt_online_schema_change::main(@args, - 'D=mkosc,t=a', qw(--drop-old-table)) }, +test_alter_table( + name => "Basic no fks --dry-run", + table => "pt_osc.t", + file => "basic_no_fks.sql", + max_id => 20, + test_type => "new_engine", + new_engine => "MyISAM", + cmds => [qw(--dry-run --alter ENGINE=InnoDB)], ); -$rows = $dbh->selectall_hashref('show table status from mkosc', 'name'); -is( - $rows->{a}->{engine}, - 'MyISAM', - "No --alter, new table still ENGINE=MyISAM" +test_alter_table( + name => "Basic no fks --execute", + table => "pt_osc.t", + # The previous test should not have modified the table. + # file => "basic_no_fks.sql", + # max_id => 20, + test_type => "new_engine", + new_engine => "InnoDB", + cmds => [qw(--execute --alter ENGINE=InnoDB)], ); -ok( - !exists $rows->{__old_a}, - "--drop-old-table" -); - -$new_rows = $dbh->selectall_arrayref('select * from mkosc.a order by i'); -is_deeply( - $new_rows, - $org_rows, # from previous run since old table was dropped this run - "New tables rows identical to old table rows" -); - -is( - $exit, - 0, - "Exit status 0" +test_alter_table( + name => "--execute but no --alter", + table => "pt_osc.t", + file => "basic_no_fks.sql", + max_id => 20, + test_type => "new_engine", + new_engine => "MyISAM", + cmds => [qw(--execute)], ); # ############################################################################ @@ -167,82 +244,93 @@ is( # ############################################################################ # The tables we're loading have fk constraints like: -# country -# ^- city (on update cascade) -# ^- address (on update cascade) +# country <-- city <-- address -############################ -# rebuild_constraints method -############################ -$sb->load_file('master', "t/pt-online-schema-change/samples/fk_tables_schema.sql"); +# rebuild_constraints method -- This parses the fk constraint ddls from +# the create table ddl, rewrites them, then does an alter table on the +# child tables so they point back to the original table name. -# city has a fk constraint on country, so get its original table def. -my $orig_table_def = $dbh->selectrow_hashref('show create table mkosc.city')->{'create table'}; - -# Alter the parent table. The error we need to avoid is: -# DBD::mysql::db do failed: Cannot delete or update a parent row: -# a foreign key constraint fails [for Statement "DROP TABLE -# `mkosc`.`__old_country`"] -output( - sub { $exit = pt_online_schema_change::main(@args, - 'D=mkosc,t=country', qw(--child-tables auto_detect --drop-old-table), - qw(--update-foreign-keys-method rebuild_constraints)) }, -); -is( - $exit, - 0, - "Exit status 0 (rebuild_constraints method)" +test_alter_table( + name => "Basic FK rebuild --dry-run", + table => "pt_osc.country", + pk_col => "country_id", + file => "basic_with_fks.sql", + wait => ["pt_osc.address", "address_id=5"], + test_type => "drop_col", + drop_col => "last_update", + check_fks => 1, + cmds => [ + qw( + --dry-run + --find-child-tables + --update-foreign-keys-method rebuild_constraints + ), + '--alter', 'DROP COLUMN last_update', + ], ); -$rows = $dbh->selectall_arrayref('show tables from mkosc like "\_\_%"'); -is_deeply( - $rows, - [], - "Old table dropped (rebuild_constraints method)" +test_alter_table( + name => "Basic FK rebuild --execute", + table => "pt_osc.country", + pk_col => "country_id", + # The previous test should not have modified the table. + # file => "basic_with_fks.sql", + # wait => ["pt_osc.address", "address_id=5"], + test_type => "drop_col", + drop_col => "last_update", + check_fks => 1, + cmds => [ + qw( + --execute + --find-child-tables + --update-foreign-keys-method rebuild_constraints + ), + '--alter', 'DROP COLUMN last_update', + ], ); -# Get city's table def again and verify that its fk constraint still -# references country. When country was renamed to __old_country, MySQL -# also updated city's fk constraint to __old_country. We should have -# dropped and re-added that constraint exactly, changing only __old_country -# to country, like it originally was. -my $new_table_def = $dbh->selectrow_hashref('show create table mkosc.city')->{'create table'}; -is( - $new_table_def, - $orig_table_def, - "Updated child table foreign key constraint (rebuild_constraints method)" +# drop_old_table method -- This method tricks MySQL by disabling fk checks, +# then dropping the original table and renaming the new table in its place. +# Since fk checks were disabled, MySQL doesn't update the child table fk refs. +# Somewhat dangerous, but quick. Downside: table doesn't exist for a moment. + +test_alter_table( + name => "Basic FK drop-swap --dry-run", + table => "pt_osc.country", + pk_col => "country_id", + file => "basic_with_fks.sql", + wait => ["pt_osc.address", "address_id=5"], + test_type => "drop_col", + drop_col => "last_update", + check_fks => 1, + cmds => [ + qw( + --dry-run + --find-child-tables + --update-foreign-keys-method drop_old_table + ), + '--alter', 'DROP COLUMN last_update', + ], ); -####################### -# drop_old_table method -####################### -$sb->load_file('master', "t/pt-online-schema-change/samples/fk_tables_schema.sql"); - -$orig_table_def = $dbh->selectrow_hashref('show create table mkosc.city')->{'create table'}; - -output( - sub { $exit = pt_online_schema_change::main(@args, - 'D=mkosc,t=country', qw(--child-tables auto_detect), - qw(--update-foreign-keys-method drop_old_table)) }, -); -is( - $exit, - 0, - "Exit status 0 (drop_old_table method)" -); - -$rows = $dbh->selectall_arrayref('show tables from mkosc like "\_\_%"'); -is_deeply( - $rows, - [], - "Old table dropped (drop_old_table method)" -) or print Dumper($rows); - -$new_table_def = $dbh->selectrow_hashref('show create table mkosc.city')->{'create table'}; -is( - $new_table_def, - $orig_table_def, - "Updated child table foreign key constraint (drop_old_table method)" +test_alter_table( + name => "Basic FK drop-swap --execute", + table => "pt_osc.country", + pk_col => "country_id", + # The previous test should not have modified the table. + # file => "basic_with_fks.sql", + # wait => ["pt_osc.address", "address_id=5"], + test_type => "drop_col", + drop_col => "last_update", + check_fks => 1, + cmds => [ + qw( + --execute + --find-child-tables + --update-foreign-keys-method drop_old_table + ), + '--alter', 'DROP COLUMN last_update', + ], ); # ############################################################################# @@ -253,19 +341,19 @@ sub test_table { my ($file, $name) = @args{qw(file name)}; $sb->load_file('master', "t/lib/samples/osc/$file"); - PerconaTest::wait_for_table($dbh, "osc.t", "id=5"); - PerconaTest::wait_for_table($dbh, "osc.__new_t"); - $dbh->do('use osc'); - $dbh->do("DROP TABLE IF EXISTS osc.__new_t"); + PerconaTest::wait_for_table($master_dbh, "osc.t", "id=5"); + PerconaTest::wait_for_table($master_dbh, "osc.__new_t"); + $master_dbh->do('use osc'); + $master_dbh->do("DROP TABLE IF EXISTS osc.__new_t"); - $org_rows = $dbh->selectall_arrayref('select * from osc.t order by id'); + my $org_rows = $master_dbh->selectall_arrayref('select * from osc.t order by id'); output( sub { $exit = pt_online_schema_change::main(@args, - 'D=osc,t=t', qw(--alter ENGINE=InnoDB)) }, + "$dsn,D=osc,t=t", qw(--alter ENGINE=InnoDB)) }, ); - $new_rows = $dbh->selectall_arrayref('select * from osc.t order by id'); + my $new_rows = $master_dbh->selectall_arrayref('select * from osc.t order by id'); is_deeply( $new_rows, @@ -293,5 +381,5 @@ test_table( # ############################################################################# # Done. # ############################################################################# -$sb->wipe_clean($dbh); +$sb->wipe_clean($master_dbh); exit; diff --git a/t/pt-online-schema-change/samples/small_table.sql b/t/pt-online-schema-change/samples/basic_no_fks.sql similarity index 55% rename from t/pt-online-schema-change/samples/small_table.sql rename to t/pt-online-schema-change/samples/basic_no_fks.sql index b437e962..f0928b42 100644 --- a/t/pt-online-schema-change/samples/small_table.sql +++ b/t/pt-online-schema-change/samples/basic_no_fks.sql @@ -1,12 +1,13 @@ -DROP DATABASE IF EXISTS `mkosc`; -CREATE DATABASE `mkosc`; -USE `mkosc`; -CREATE TABLE a ( - i int auto_increment primary key, - c char(16), - d date +DROP DATABASE IF EXISTS pt_osc; +CREATE DATABASE pt_osc; +USE pt_osc; +CREATE TABLE t ( + id int auto_increment primary key, + c char(16), + d date, + unique index (c(16)) ) ENGINE=MyISAM; -INSERT INTO a VALUES +INSERT INTO pt_osc.t VALUES (null, 'a', now()), (null, 'b', now()), (null, 'c', now()), @@ -16,7 +17,7 @@ INSERT INTO a VALUES (null, 'g', now()), (null, 'h', now()), (null, 'i', now()), - (null, 'j', now()), + (null, 'j', now()), -- 10 (null, 'k', now()), (null, 'l', now()), (null, 'm', now()), @@ -24,4 +25,6 @@ INSERT INTO a VALUES (null, 'o', now()), (null, 'p', now()), (null, 'q', now()), - (null, 'r', now()); + (null, 'r', now()), + (null, 's', now()), + (null, 't', now()); -- 20 diff --git a/t/pt-online-schema-change/samples/fk_tables_schema.sql b/t/pt-online-schema-change/samples/basic_with_fks.sql similarity index 63% rename from t/pt-online-schema-change/samples/fk_tables_schema.sql rename to t/pt-online-schema-change/samples/basic_with_fks.sql index aabf2e1e..c98bd6c2 100644 --- a/t/pt-online-schema-change/samples/fk_tables_schema.sql +++ b/t/pt-online-schema-change/samples/basic_with_fks.sql @@ -1,6 +1,8 @@ -DROP DATABASE IF EXISTS `mkosc`; -CREATE DATABASE `mkosc`; -USE `mkosc`; +DROP DATABASE IF EXISTS pt_osc; +CREATE DATABASE pt_osc; +USE pt_osc; + +SET foreign_key_checks=0; CREATE TABLE `country` ( `country_id` smallint(5) unsigned NOT NULL AUTO_INCREMENT, @@ -29,3 +31,26 @@ CREATE TABLE `address` ( KEY `idx_fk_city_id` (`city_id`), CONSTRAINT `fk_address_city` FOREIGN KEY (`city_id`) REFERENCES `city` (`city_id`) ON UPDATE CASCADE ) ENGINE=InnoDB; + +INSERT INTO pt_osc.country VALUES + (1, 'Canada', null), + (2, 'USA', null), + (3, 'Mexico', null), + (4, 'France', null), + (5, 'Spain', null); + +INSERT INTO pt_osc.city VALUES + (null, 'Montréal', 1, null), + (null, 'New York', 2, null), + (null, 'Durango', 3, null), + (null, 'Paris', 4, null), + (null, 'Madrid', 5, null); + +INSERT INTO pt_osc.address VALUES + (null, 'addy 1', 1, '10000', null), + (null, 'addy 2', 2, '20000', null), + (null, 'addy 3', 3, '30000', null), + (null, 'addy 4', 4, '40000', null), + (null, 'addy 5', 5, '50000', null); + +SET foreign_key_checks=1;