6a4ce404f1dc23006f8ff4e5e8c097bb2727cde3
[dbsrgits/SQL-Translator.git] / t / 30sqlt-new-diff-mysql.t
1 #!/usr/bin/perl
2 # vim: set ft=perl:
3
4 use strict;
5 use warnings;
6 use SQL::Translator;
7
8 use File::Spec::Functions qw(catfile updir tmpdir);
9 use FindBin qw($Bin);
10 use Test::More;
11 use Test::Differences;
12 use Test::SQL::Translator qw(maybe_plan);
13 use SQL::Translator::Schema::Constants;
14 use Storable 'dclone';
15
16 plan tests => 9;
17
18 use_ok('SQL::Translator::Diff') or die "Cannot continue\n";
19
20 my $tr = SQL::Translator->new;
21
22 my ( $source_schema, $target_schema, $parsed_sql_schema ) = map {
23     my $t = SQL::Translator->new;
24     $t->parser( 'YAML' )
25       or die $tr->error;
26     my $out = $t->translate( catfile($Bin, qw/data diff/, $_ ) )
27       or die $tr->error;
28
29     my $schema = $t->schema;
30     unless ( $schema->name ) {
31         $schema->name( $_ );
32     }
33     ($schema);
34 } (qw( create1.yml create2.yml ));
35
36 # Test for differences
37 my @out = SQL::Translator::Diff::schema_diff(
38     $source_schema, 'MySQL',
39     $target_schema, 'MySQL',
40     {
41         no_batch_alters  => 1,
42         producer_args => { quote_table_names => 0 }
43     }
44 );
45
46 ok( @out, 'Got a list' );
47
48 my $out = join('', @out);
49
50 eq_or_diff($out, <<'## END OF DIFF', "Diff as expected");
51 -- Convert schema 'create1.yml' to 'create2.yml':;
52
53 BEGIN;
54
55 SET foreign_key_checks=0;
56
57 CREATE TABLE added (
58   id integer(11) NULL
59 );
60
61 SET foreign_key_checks=1;
62
63 ALTER TABLE old_name RENAME TO new_name;
64
65 ALTER TABLE employee DROP FOREIGN KEY FK5302D47D93FE702E;
66
67 ALTER TABLE person DROP INDEX UC_age_name;
68
69 ALTER TABLE person DROP INDEX u_name;
70
71 ALTER TABLE employee DROP COLUMN job_title;
72
73 ALTER TABLE new_name ADD COLUMN new_field integer NULL;
74
75 ALTER TABLE person ADD COLUMN is_rock_star tinyint(4) NULL DEFAULT 1;
76
77 ALTER TABLE person CHANGE COLUMN person_id person_id integer(11) NOT NULL auto_increment;
78
79 ALTER TABLE person CHANGE COLUMN name name varchar(20) NOT NULL;
80
81 ALTER TABLE person CHANGE COLUMN age age integer(11) NULL DEFAULT 18;
82
83 ALTER TABLE person CHANGE COLUMN iq iq integer(11) NULL DEFAULT 0;
84
85 ALTER TABLE person CHANGE COLUMN description physical_description text NULL;
86
87 ALTER TABLE person ADD UNIQUE INDEX unique_name (name);
88
89 ALTER TABLE employee ADD CONSTRAINT FK5302D47D93FE702E_diff FOREIGN KEY (employee_id) REFERENCES person (person_id);
90
91 ALTER TABLE person ADD UNIQUE UC_person_id (person_id);
92
93 ALTER TABLE person ADD UNIQUE UC_age_name (age, name);
94
95 ALTER TABLE person ENGINE=InnoDB;
96
97 ALTER TABLE deleted DROP FOREIGN KEY fk_fake;
98
99 DROP TABLE deleted;
100
101
102 COMMIT;
103
104 ## END OF DIFF
105
106 $out = SQL::Translator::Diff::schema_diff($source_schema, 'MySQL', $target_schema, 'MySQL',
107     { ignore_index_names => 1,
108       ignore_constraint_names => 1,
109       producer_args => { quote_table_names => 0 },
110     });
111
112 eq_or_diff($out, <<'## END OF DIFF', "Diff as expected");
113 -- Convert schema 'create1.yml' to 'create2.yml':;
114
115 BEGIN;
116
117 SET foreign_key_checks=0;
118
119 CREATE TABLE added (
120   id integer(11) NULL
121 );
122
123 SET foreign_key_checks=1;
124
125 ALTER TABLE employee DROP COLUMN job_title;
126
127 ALTER TABLE old_name RENAME TO new_name,
128                      ADD COLUMN new_field integer NULL;
129
130 ALTER TABLE person DROP INDEX UC_age_name,
131                    ADD COLUMN is_rock_star tinyint(4) NULL DEFAULT 1,
132                    CHANGE COLUMN person_id person_id integer(11) NOT NULL auto_increment,
133                    CHANGE COLUMN name name varchar(20) NOT NULL,
134                    CHANGE COLUMN age age integer(11) NULL DEFAULT 18,
135                    CHANGE COLUMN iq iq integer(11) NULL DEFAULT 0,
136                    CHANGE COLUMN description physical_description text NULL,
137                    ADD UNIQUE UC_person_id (person_id),
138                    ADD UNIQUE UC_age_name (age, name),
139                    ENGINE=InnoDB;
140
141 ALTER TABLE deleted DROP FOREIGN KEY fk_fake;
142
143 DROP TABLE deleted;
144
145
146 COMMIT;
147
148 ## END OF DIFF
149
150
151 # Test for sameness
152 $out = SQL::Translator::Diff::schema_diff($source_schema, 'MySQL', $source_schema, 'MySQL' );
153
154 eq_or_diff($out, <<'## END OF DIFF', "No differences found");
155 -- Convert schema 'create1.yml' to 'create1.yml':;
156
157 -- No differences found;
158
159 ## END OF DIFF
160
161 {
162   my $t = SQL::Translator->new;
163   $t->parser( 'MySQL' )
164     or die $tr->error;
165   my $out = $t->translate( catfile($Bin, qw/data mysql create.sql/ ) )
166     or die $tr->error;
167
168   # Lets remove the renamed table so we dont have to change the SQL or other tests
169   $target_schema->drop_table('new_name');
170
171   my $schema = $t->schema;
172   unless ( $schema->name ) {
173       $schema->name( 'create.sql' );
174   }
175
176   # Now lets change the type of one of the 'integer' columns so that it
177   # matches what the mysql parser sees for '<col> interger'.
178   my $field = $target_schema->get_table('employee')->get_field('employee_id');
179   $field->data_type('integer');
180   $field->size(0);
181   $out = SQL::Translator::Diff::schema_diff($schema, 'MySQL', $target_schema, 'MySQL', { producer_args => { quote_table_names => 0 } } );
182   eq_or_diff($out, <<'## END OF DIFF', "No differences found");
183 -- Convert schema 'create.sql' to 'create2.yml':;
184
185 BEGIN;
186
187 SET foreign_key_checks=0;
188
189 CREATE TABLE added (
190   id integer(11) NULL
191 );
192
193 SET foreign_key_checks=1;
194
195 ALTER TABLE employee DROP FOREIGN KEY FK5302D47D93FE702E,
196                      DROP COLUMN job_title,
197                      ADD CONSTRAINT FK5302D47D93FE702E_diff FOREIGN KEY (employee_id) REFERENCES person (person_id);
198
199 ALTER TABLE person DROP INDEX UC_age_name,
200                    DROP INDEX u_name,
201                    ADD COLUMN is_rock_star tinyint(4) NULL DEFAULT 1,
202                    ADD COLUMN value double(8, 2) NULL DEFAULT 0.00,
203                    CHANGE COLUMN person_id person_id integer(11) NOT NULL auto_increment,
204                    CHANGE COLUMN name name varchar(20) NOT NULL,
205                    CHANGE COLUMN age age integer(11) NULL DEFAULT 18,
206                    CHANGE COLUMN iq iq integer(11) NULL DEFAULT 0,
207                    CHANGE COLUMN description physical_description text NULL,
208                    ADD UNIQUE INDEX unique_name (name),
209                    ADD UNIQUE UC_person_id (person_id),
210                    ADD UNIQUE UC_age_name (age, name),
211                    ENGINE=InnoDB;
212
213 DROP TABLE deleted;
214
215
216 COMMIT;
217
218 ## END OF DIFF
219 }
220
221 # Test InnoDB stupidness. Have to drop constraints before re-adding them if
222 # they are just alters.
223
224
225 {
226   my $s1 = SQL::Translator::Schema->new;
227   my $s2 = SQL::Translator::Schema->new;
228
229   $s1->name('Schema 1');
230   $s2->name('Schema 2');
231
232   my $t1 = $s1->add_table($target_schema->get_table('employee'));
233   my $t2 = $s2->add_table(dclone($target_schema->get_table('employee')));
234
235
236   my ($c) = grep { $_->name eq 'FK5302D47D93FE702E_diff' } $t2->get_constraints;
237   $c->on_delete('CASCADE');
238
239   $t2->add_constraint(
240     name => 'new_constraint',
241     type => 'FOREIGN KEY',
242     fields => ['employee_id'],
243     reference_fields => ['fake'],
244     reference_table => 'patty',
245   );
246
247   $t2->add_field(
248     name => 'new',
249     data_type => 'int'
250   );
251
252   my $out = SQL::Translator::Diff::schema_diff($s1, 'MySQL', $s2, 'MySQL' );
253
254   eq_or_diff($out, <<'## END OF DIFF', "Batch alter of constraints work for InnoDB");
255 -- Convert schema 'Schema 1' to 'Schema 2':;
256
257 BEGIN;
258
259 ALTER TABLE employee DROP FOREIGN KEY FK5302D47D93FE702E_diff;
260
261 ALTER TABLE employee ADD COLUMN new integer NULL,
262                      ADD CONSTRAINT FK5302D47D93FE702E_diff FOREIGN KEY (employee_id) REFERENCES person (person_id) ON DELETE CASCADE,
263                      ADD CONSTRAINT new_constraint FOREIGN KEY (employee_id) REFERENCES patty (fake);
264
265
266 COMMIT;
267
268 ## END OF DIFF
269 }
270
271 {
272   # Test other things about renaming tables to - namely that renames
273   # constraints are still formated right.
274
275   my $s1 = SQL::Translator::Schema->new;
276   my $s2 = SQL::Translator::Schema->new;
277
278   $s1->name('Schema 3');
279   $s2->name('Schema 4');
280
281   my $t1 = $s1->add_table(dclone($target_schema->get_table('employee')));
282   my $t2 = dclone($target_schema->get_table('employee'));
283   $t2->name('fnord');
284   $t2->extra(renamed_from => 'employee');
285   $s2->add_table($t2);
286
287
288   $t1->add_constraint(
289     name => 'bar_fk',
290     type => 'FOREIGN KEY',
291     fields => ['employee_id'],
292     reference_fields => ['id'],
293     reference_table => 'bar',
294   );
295   $t2->add_constraint(
296     name => 'foo_fk',
297     type => 'FOREIGN KEY',
298     fields => ['employee_id'],
299     reference_fields => ['id'],
300     reference_table => 'foo',
301   );
302
303   my $out = SQL::Translator::Diff::schema_diff($s1, 'MySQL', $s2, 'MySQL' );
304   eq_or_diff($out, <<'## END OF DIFF', "Alter/drop constraints works with rename table");
305 -- Convert schema 'Schema 3' to 'Schema 4':;
306
307 BEGIN;
308
309 ALTER TABLE employee RENAME TO fnord,
310                      DROP FOREIGN KEY bar_fk,
311                      ADD CONSTRAINT foo_fk FOREIGN KEY (employee_id) REFERENCES foo (id);
312
313
314 COMMIT;
315
316 ## END OF DIFF
317
318   # Test quoting works too.
319   $out = SQL::Translator::Diff::schema_diff($s1, 'MySQL', $s2, 'MySQL',
320     { producer_args => { quote_table_names => '`' } }
321   );
322   eq_or_diff($out, <<'## END OF DIFF', "Quoting can be turned on");
323 -- Convert schema 'Schema 3' to 'Schema 4':;
324
325 BEGIN;
326
327 ALTER TABLE `employee` RENAME TO `fnord`,
328                        DROP FOREIGN KEY bar_fk,
329                        ADD CONSTRAINT foo_fk FOREIGN KEY (employee_id) REFERENCES `foo` (id);
330
331
332 COMMIT;
333
334 ## END OF DIFF
335 }