Make MySQL producer add NULL for every nullable field
[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                    CHANGE COLUMN person_id person_id integer(11) NOT NULL auto_increment,
203                    CHANGE COLUMN name name varchar(20) NOT NULL,
204                    CHANGE COLUMN age age integer(11) NULL DEFAULT 18,
205                    CHANGE COLUMN iq iq integer(11) NULL DEFAULT 0,
206                    CHANGE COLUMN description physical_description text NULL,
207                    ADD UNIQUE INDEX unique_name (name),
208                    ADD UNIQUE UC_person_id (person_id),
209                    ADD UNIQUE UC_age_name (age, name),
210                    ENGINE=InnoDB;
211
212 DROP TABLE deleted;
213
214
215 COMMIT;
216
217 ## END OF DIFF
218 }
219
220 # Test InnoDB stupidness. Have to drop constraints before re-adding them if
221 # they are just alters.
222
223
224 {
225   my $s1 = SQL::Translator::Schema->new;
226   my $s2 = SQL::Translator::Schema->new;
227
228   $s1->name('Schema 1');
229   $s2->name('Schema 2');
230
231   my $t1 = $s1->add_table($target_schema->get_table('employee'));
232   my $t2 = $s2->add_table(dclone($target_schema->get_table('employee')));
233
234
235   my ($c) = grep { $_->name eq 'FK5302D47D93FE702E_diff' } $t2->get_constraints;
236   $c->on_delete('CASCADE');
237
238   $t2->add_constraint(
239     name => 'new_constraint',
240     type => 'FOREIGN KEY',
241     fields => ['employee_id'],
242     reference_fields => ['fake'],
243     reference_table => 'patty',
244   );
245
246   $t2->add_field(
247     name => 'new',
248     data_type => 'int'
249   );
250
251   my $out = SQL::Translator::Diff::schema_diff($s1, 'MySQL', $s2, 'MySQL' );
252
253   eq_or_diff($out, <<'## END OF DIFF', "Batch alter of constraints work for InnoDB");
254 -- Convert schema 'Schema 1' to 'Schema 2':;
255
256 BEGIN;
257
258 ALTER TABLE employee DROP FOREIGN KEY FK5302D47D93FE702E_diff;
259
260 ALTER TABLE employee ADD COLUMN new integer NULL,
261                      ADD CONSTRAINT FK5302D47D93FE702E_diff FOREIGN KEY (employee_id) REFERENCES person (person_id) ON DELETE CASCADE,
262                      ADD CONSTRAINT new_constraint FOREIGN KEY (employee_id) REFERENCES patty (fake);
263
264
265 COMMIT;
266
267 ## END OF DIFF
268 }
269
270 {
271   # Test other things about renaming tables to - namely that renames
272   # constraints are still formated right.
273
274   my $s1 = SQL::Translator::Schema->new;
275   my $s2 = SQL::Translator::Schema->new;
276
277   $s1->name('Schema 3');
278   $s2->name('Schema 4');
279
280   my $t1 = $s1->add_table(dclone($target_schema->get_table('employee')));
281   my $t2 = dclone($target_schema->get_table('employee'));
282   $t2->name('fnord');
283   $t2->extra(renamed_from => 'employee');
284   $s2->add_table($t2);
285
286
287   $t1->add_constraint(
288     name => 'bar_fk',
289     type => 'FOREIGN KEY',
290     fields => ['employee_id'],
291     reference_fields => ['id'],
292     reference_table => 'bar',
293   );
294   $t2->add_constraint(
295     name => 'foo_fk',
296     type => 'FOREIGN KEY',
297     fields => ['employee_id'],
298     reference_fields => ['id'],
299     reference_table => 'foo',
300   );
301
302   my $out = SQL::Translator::Diff::schema_diff($s1, 'MySQL', $s2, 'MySQL' );
303   eq_or_diff($out, <<'## END OF DIFF', "Alter/drop constraints works with rename table");
304 -- Convert schema 'Schema 3' to 'Schema 4':;
305
306 BEGIN;
307
308 ALTER TABLE employee RENAME TO fnord,
309                      DROP FOREIGN KEY bar_fk,
310                      ADD CONSTRAINT foo_fk FOREIGN KEY (employee_id) REFERENCES foo (id);
311
312
313 COMMIT;
314
315 ## END OF DIFF
316
317   # Test quoting works too.
318   $out = SQL::Translator::Diff::schema_diff($s1, 'MySQL', $s2, 'MySQL',
319     { producer_args => { quote_table_names => '`' } }
320   );
321   eq_or_diff($out, <<'## END OF DIFF', "Quoting can be turned on");
322 -- Convert schema 'Schema 3' to 'Schema 4':;
323
324 BEGIN;
325
326 ALTER TABLE `employee` RENAME TO `fnord`,
327                        DROP FOREIGN KEY bar_fk,
328                        ADD CONSTRAINT foo_fk FOREIGN KEY (employee_id) REFERENCES `foo` (id);
329
330
331 COMMIT;
332
333 ## END OF DIFF
334 }