Release commit for 1.62
[dbsrgits/SQL-Translator.git] / t / 02mysql-parser.t
CommitLineData
0494e672 1#!/usr/bin/perl
2# vim: set ft=perl:
3#
0494e672 4
b8661f30 5use strict;
44fb27ae 6
fbc0552f 7use Test::More;
b8661f30 8use SQL::Translator;
2ab84c11 9use SQL::Translator::Schema::Constants;
5d666b31 10use SQL::Translator::Utils qw//;
2d691ec1 11use Test::SQL::Translator qw(maybe_plan);
d0a4031c 12use FindBin qw/$Bin/;
0494e672 13
2d691ec1 14BEGIN {
2c1e8cab 15 maybe_plan(undef, "SQL::Translator::Parser::MySQL");
fbc0552f 16 SQL::Translator::Parser::MySQL->import('parse');
fbc0552f 17}
18
251b6ff5 19{
20 my $tr = SQL::Translator->new;
6acd7c95 21 my $data = q|create table "sessions" (
2ab84c11 22 id char(32) not null default '0' primary key,
2e8b8523 23 a_session text,
24 ssn varchar(12) unique key,
a383e9e9 25 age int key,
26 fulltext key `session_fulltext` (a_session)
251b6ff5 27 );|;
28
29 my $val = parse($tr, $data);
2ab84c11 30 my $schema = $tr->schema;
e3252059 31 is( $schema->is_valid, 1, 'Schema is valid' );
2ab84c11 32 my @tables = $schema->get_tables;
33 is( scalar @tables, 1, 'Right number of tables (1)' );
34 my $table = shift @tables;
35 is( $table->name, 'sessions', 'Found "sessions" table' );
251b6ff5 36
2ab84c11 37 my @fields = $table->get_fields;
2e8b8523 38 is( scalar @fields, 4, 'Right number of fields (4)' );
2ab84c11 39 my $f1 = shift @fields;
40 my $f2 = shift @fields;
41 is( $f1->name, 'id', 'First field name is "id"' );
42 is( $f1->data_type, 'char', 'Type is "char"' );
43 is( $f1->size, 32, 'Size is "32"' );
44 is( $f1->is_nullable, 0, 'Field cannot be null' );
45 is( $f1->default_value, '0', 'Default value is "0"' );
46 is( $f1->is_primary_key, 1, 'Field is PK' );
251b6ff5 47
2ab84c11 48 is( $f2->name, 'a_session', 'Second field name is "a_session"' );
49 is( $f2->data_type, 'text', 'Type is "text"' );
0c1c8d2a 50 is( $f2->size, 65_535, 'Size is "65,535"' );
2ab84c11 51 is( $f2->is_nullable, 1, 'Field can be null' );
52 is( $f2->default_value, undef, 'Default value is undefined' );
53 is( $f2->is_primary_key, 0, 'Field is not PK' );
251b6ff5 54
2ab84c11 55 my @indices = $table->get_indices;
a383e9e9 56 is( scalar @indices, 2, 'Right number of indices (2)' );
57 my $i = pop @indices;
58 is( $i->type, 'FULLTEXT', 'Found fulltext' );
251b6ff5 59
2ab84c11 60 my @constraints = $table->get_constraints;
2e8b8523 61 is( scalar @constraints, 2, 'Right number of constraints (2)' );
2ab84c11 62 my $c = shift @constraints;
63 is( $c->type, PRIMARY_KEY, 'Constraint is a PK' );
64 is( join(',', $c->fields), 'id', 'Constraint is on "id"' );
2e8b8523 65 my $c2 = shift @constraints;
66 is( $c2->type, UNIQUE, 'Constraint is UNIQUE' );
67 is( join(',', $c2->fields), 'ssn', 'Constraint is on "ssn"' );
251b6ff5 68}
69
70{
71 my $tr = SQL::Translator->new;
aee4b66e 72 my $data = parse($tr,
251b6ff5 73 q[
6acd7c95 74 CREATE TABLE `check` (
aee4b66e 75 check_id int(7) unsigned zerofill NOT NULL default '0000000'
251b6ff5 76 auto_increment primary key,
77 successful date NOT NULL default '0000-00-00',
78 unsuccessful date default '0000-00-00',
79 i1 int(11) default '0' not null,
80 s1 set('a','b','c') default 'b',
46417fe2 81 e1 enum("a","b","c") default "c",
251b6ff5 82 name varchar(30) default NULL,
1868ddbe 83 foo_type enum('vk','c''k') NOT NULL default 'vk',
251b6ff5 84 date timestamp,
85 time_stamp2 timestamp,
bc9932bf 86 foo_enabled bit(1) default b'0',
87 bar_enabled bit(1) default b"1",
b98bd48d 88 long_foo_enabled bit(10) default b'1010101',
251b6ff5 89 KEY (i1),
62a64f6c 90 UNIQUE (date, i1) USING BTREE,
251b6ff5 91 KEY date_idx (date),
92 KEY name_idx (name(10))
93 ) TYPE=MyISAM PACK_KEYS=1;
94 ]
95 );
aee4b66e 96
2ab84c11 97 my $schema = $tr->schema;
e3252059 98 is( $schema->is_valid, 1, 'Schema is valid' );
2ab84c11 99 my @tables = $schema->get_tables;
100 is( scalar @tables, 1, 'Right number of tables (1)' );
101 my $table = shift @tables;
102 is( $table->name, 'check', 'Found "check" table' );
103
104 my @fields = $table->get_fields;
b98bd48d 105 is( scalar @fields, 13, 'Right number of fields (13)' );
2ab84c11 106 my $f1 = shift @fields;
107 is( $f1->name, 'check_id', 'First field name is "check_id"' );
108 is( $f1->data_type, 'int', 'Type is "int"' );
109 is( $f1->size, 7, 'Size is "7"' );
110 is( $f1->is_nullable, 0, 'Field cannot be null' );
111 is( $f1->default_value, '0000000', 'Default value is "0000000"' );
112 is( $f1->is_primary_key, 1, 'Field is PK' );
113 is( $f1->is_auto_increment, 1, 'Field is auto inc' );
114 my %extra = $f1->extra;
115 ok( defined $extra{'unsigned'}, 'Field is unsigned' );
116 ok( defined $extra{'zerofill'}, 'Field is zerofill' );
117
118 my $f2 = shift @fields;
119 is( $f2->name, 'successful', 'Second field name is "successful"' );
120 is( $f2->data_type, 'date', 'Type is "date"' );
121 is( $f2->size, 0, 'Size is "0"' );
122 is( $f2->is_nullable, 0, 'Field cannot be null' );
123 is( $f2->default_value, '0000-00-00', 'Default value is "0000-00-00"' );
124 is( $f2->is_primary_key, 0, 'Field is not PK' );
125
126 my $f3 = shift @fields;
127 is( $f3->name, 'unsuccessful', 'Third field name is "unsuccessful"' );
128 is( $f3->data_type, 'date', 'Type is "date"' );
129 is( $f3->size, 0, 'Size is "0"' );
130 is( $f3->is_nullable, 1, 'Field can be null' );
131 is( $f3->default_value, '0000-00-00', 'Default value is "0000-00-00"' );
132 is( $f3->is_primary_key, 0, 'Field is not PK' );
133
134 my $f4 = shift @fields;
135 is( $f4->name, 'i1', 'Fourth field name is "i1"' );
136 is( $f4->data_type, 'int', 'Type is "int"' );
137 is( $f4->size, 11, 'Size is "11"' );
138 is( $f4->is_nullable, 0, 'Field cannot be null' );
139 is( $f4->default_value, '0', 'Default value is "0"' );
140 is( $f4->is_primary_key, 0, 'Field is not PK' );
3a0b6f0a 141
2ab84c11 142 my $f5 = shift @fields;
143 is( $f5->name, 's1', 'Fifth field name is "s1"' );
144 is( $f5->data_type, 'set', 'Type is "set"' );
145 is( $f5->size, 1, 'Size is "1"' );
146 is( $f5->is_nullable, 1, 'Field can be null' );
147 is( $f5->default_value, 'b', 'Default value is "b"' );
148 is( $f5->is_primary_key, 0, 'Field is not PK' );
149 my %f5extra = $f5->extra;
150 is( join(',', @{ $f5extra{'list'} || [] }), 'a,b,c', 'List is "a,b,c"' );
3a0b6f0a 151
2ab84c11 152 my $f6 = shift @fields;
153 is( $f6->name, 'e1', 'Sixth field name is "e1"' );
154 is( $f6->data_type, 'enum', 'Type is "enum"' );
155 is( $f6->size, 1, 'Size is "1"' );
156 is( $f6->is_nullable, 1, 'Field can be null' );
157 is( $f6->default_value, 'c', 'Default value is "c"' );
158 is( $f6->is_primary_key, 0, 'Field is not PK' );
159 my %f6extra = $f6->extra;
160 is( join(',', @{ $f6extra{'list'} || [] }), 'a,b,c', 'List is "a,b,c"' );
3a0b6f0a 161
2ab84c11 162 my $f7 = shift @fields;
163 is( $f7->name, 'name', 'Seventh field name is "name"' );
164 is( $f7->data_type, 'varchar', 'Type is "varchar"' );
165 is( $f7->size, 30, 'Size is "30"' );
166 is( $f7->is_nullable, 1, 'Field can be null' );
167 is( $f7->default_value, 'NULL', 'Default value is "NULL"' );
168 is( $f7->is_primary_key, 0, 'Field is not PK' );
3a0b6f0a 169
2ab84c11 170 my $f8 = shift @fields;
171 is( $f8->name, 'foo_type', 'Eighth field name is "foo_type"' );
172 is( $f8->data_type, 'enum', 'Type is "enum"' );
1868ddbe 173 is( $f8->size, 3, 'Size is "2"' );
2ab84c11 174 is( $f8->is_nullable, 0, 'Field cannot be null' );
175 is( $f8->default_value, 'vk', 'Default value is "vk"' );
176 is( $f8->is_primary_key, 0, 'Field is not PK' );
177 my %f8extra = $f8->extra;
1868ddbe 178 is( join(',', @{ $f8extra{'list'} || [] }), 'vk,c\'k', 'List is "vk,c\'k"' );
2ab84c11 179
180 my $f9 = shift @fields;
181 is( $f9->name, 'date', 'Ninth field name is "date"' );
182 is( $f9->data_type, 'timestamp', 'Type is "timestamp"' );
183 is( $f9->size, 0, 'Size is "0"' );
184 is( $f9->is_nullable, 1, 'Field can be null' );
185 is( $f9->default_value, undef, 'Default value is undefined' );
186 is( $f9->is_primary_key, 0, 'Field is not PK' );
187
188 my $f10 = shift @fields;
189 is( $f10->name, 'time_stamp2', 'Tenth field name is "time_stamp2"' );
190 is( $f10->data_type, 'timestamp', 'Type is "timestamp"' );
191 is( $f10->size, 0, 'Size is "0"' );
192 is( $f10->is_nullable, 1, 'Field can be null' );
193 is( $f10->default_value, undef, 'Default value is undefined' );
194 is( $f10->is_primary_key, 0, 'Field is not PK' );
195
bc9932bf 196 my $f11 = shift @fields;
197 is( $f11->name, 'foo_enabled', 'Eleventh field name is "foo_enabled"' );
198 is( $f11->data_type, 'bit', 'Type is "bit"' );
199 is( $f11->size, 1, 'Size is "1"' );
200 is( $f11->is_nullable, 1, 'Field can be null' );
201 is( $f11->default_value, '0', 'Default value is 0' );
202 is( $f11->is_primary_key, 0, 'Field is not PK' );
203
204 my $f12 = shift @fields;
205 is( $f12->name, 'bar_enabled', 'Twelveth field name is "bar_enabled"' );
206 is( $f12->data_type, 'bit', 'Type is "bit"' );
207 is( $f12->size, 1, 'Size is "1"' );
208 is( $f12->is_nullable, 1, 'Field can be null' );
209 is( $f12->default_value, '1', 'Default value is 1' );
210 is( $f12->is_primary_key, 0, 'Field is not PK' );
b98bd48d 211
212 my $f13 = shift @fields;
213 is( $f13->name, 'long_foo_enabled', 'Thirteenth field name is "long_foo_enabled"' );
214 is( $f13->data_type, 'bit', 'Type is "bit"' );
215 is( $f13->size, 10, 'Size is "10"' );
216 is( $f13->is_nullable, 1, 'Field can be null' );
217 is( $f13->default_value, '1010101', 'Default value is 1010101' );
218 is( $f13->is_primary_key, 0, 'Field is not PK' );
bc9932bf 219
2ab84c11 220 my @indices = $table->get_indices;
221 is( scalar @indices, 3, 'Right number of indices (3)' );
222
223 my $i1 = shift @indices;
224 is( $i1->name, '', 'No name on index' );
225 is( $i1->type, NORMAL, 'Normal index' );
226 is( join(',', $i1->fields ), 'i1', 'Index is on field "i1"' );
227
228 my $i2 = shift @indices;
229 is( $i2->name, 'date_idx', 'Name is "date_idx"' );
230 is( $i2->type, NORMAL, 'Normal index' );
231 is( join(',', $i2->fields ), 'date', 'Index is on field "date"' );
232
233 my $i3 = shift @indices;
234 is( $i3->name, 'name_idx', 'Name is "name_idx"' );
235 is( $i3->type, NORMAL, 'Normal index' );
236 is( join(',', $i3->fields ), 'name(10)', 'Index is on field "name(10)"' );
237
238 my @constraints = $table->get_constraints;
239 is( scalar @constraints, 2, 'Right number of constraints (2)' );
240
241 my $c1 = shift @constraints;
242 is( $c1->type, PRIMARY_KEY, 'Constraint is a PK' );
243 is( join(',', $c1->fields), 'check_id', 'Constraint is on "check_id"' );
244
245 my $c2 = shift @constraints;
246 is( $c2->type, UNIQUE, 'Constraint is UNIQUE' );
247 is( join(',', $c2->fields), 'date,i1', 'Constraint is on "date, i1"' );
251b6ff5 248}
249
250{
251 my $tr = SQL::Translator->new;
aee4b66e 252 my $data = parse($tr,
251b6ff5 253 q[
254 CREATE TABLE orders (
13e41152 255 order_id integer NOT NULL comment ' ' auto_increment,
aaea005b 256 member_id varchar(255) comment 'fk to ''member''',
251b6ff5 257 billing_address_id int,
258 shipping_address_id int,
259 credit_card_id int,
260 status smallint NOT NULL,
261 store_id varchar(255) NOT NULL REFERENCES store,
262 tax decimal(8,2),
263 shipping_charge decimal(8,2),
264 price_paid decimal(8,2),
1f5b2625 265 PRIMARY KEY (order_id) USING BTREE,
62a64f6c 266 KEY (status) USING BTREE,
267 KEY USING BTREE (billing_address_id),
251b6ff5 268 KEY (shipping_address_id),
269 KEY (member_id, store_id),
556d0509 270 FOREIGN KEY (status) REFERENCES order_status(id) MATCH FULL ON DELETE CASCADE ON UPDATE CASCADE,
251b6ff5 271 FOREIGN KEY (billing_address_id) REFERENCES address(address_id),
272 FOREIGN KEY (shipping_address_id) REFERENCES address(address_id)
85a6c976 273 ) TYPE=INNODB COMMENT = 'orders table comment';
2ab84c11 274
275 CREATE TABLE address (
276 address_id int NOT NULL auto_increment,
277 recipient varchar(255) NOT NULL,
278 address1 varchar(255) NOT NULL,
279 address2 varchar(255),
280 city varchar(255) NOT NULL,
281 state varchar(255) NOT NULL,
282 postal_code varchar(255) NOT NULL,
283 phone varchar(255),
284 PRIMARY KEY (address_id)
285 ) TYPE=INNODB;
251b6ff5 286 ]
287 ) or die $tr->error;
288
2ab84c11 289 my $schema = $tr->schema;
e3252059 290 is( $schema->is_valid, 1, 'Schema is valid' );
2ab84c11 291 my @tables = $schema->get_tables;
292 is( scalar @tables, 2, 'Right number of tables (2)' );
293
294 my $t1 = shift @tables;
295 is( $t1->name, 'orders', 'Found "orders" table' );
85a6c976 296 is( $t1->comments, 'orders table comment', 'Table comment OK' );
2ab84c11 297
298 my @fields = $t1->get_fields;
299 is( scalar @fields, 10, 'Right number of fields (10)' );
300
301 my $f1 = shift @fields;
302 is( $f1->name, 'order_id', 'First field name is "order_id"' );
303 is( $f1->data_type, 'int', 'Type is "int"' );
304 is( $f1->size, 11, 'Size is "11"' );
305 is( $f1->is_nullable, 0, 'Field cannot be null' );
306 is( $f1->default_value, undef, 'Default value is undefined' );
307 is( $f1->is_primary_key, 1, 'Field is PK' );
308 is( $f1->is_auto_increment, 1, 'Field is auto inc' );
13e41152 309 is_deeply( [$f1->comments],[' '], 'Field comment OK' );
2ab84c11 310
311 my $f2 = shift @fields;
312 is( $f2->name, 'member_id', 'Second field name is "member_id"' );
313 is( $f2->data_type, 'varchar', 'Type is "varchar"' );
314 is( $f2->size, 255, 'Size is "255"' );
315 is( $f2->is_nullable, 1, 'Field can be null' );
aaea005b 316 is( $f2->comments, 'fk to \'member\'', 'Field comment OK' );
2ab84c11 317 is( $f2->default_value, undef, 'Default value is undefined' );
318
319 my $f3 = shift @fields;
aee4b66e 320 is( $f3->name, 'billing_address_id',
2ab84c11 321 'Third field name is "billing_address_id"' );
322 is( $f3->data_type, 'int', 'Type is "int"' );
323 is( $f3->size, 11, 'Size is "11"' );
324
325 my $f4 = shift @fields;
aee4b66e 326 is( $f4->name, 'shipping_address_id',
2ab84c11 327 'Fourth field name is "shipping_address_id"' );
328 is( $f4->data_type, 'int', 'Type is "int"' );
329 is( $f4->size, 11, 'Size is "11"' );
330
331 my $f5 = shift @fields;
332 is( $f5->name, 'credit_card_id', 'Fifth field name is "credit_card_id"' );
333 is( $f5->data_type, 'int', 'Type is "int"' );
334 is( $f5->size, 11, 'Size is "11"' );
335
336 my $f6 = shift @fields;
337 is( $f6->name, 'status', 'Sixth field name is "status"' );
338 is( $f6->data_type, 'smallint', 'Type is "smallint"' );
339 is( $f6->size, 6, 'Size is "6"' );
340 is( $f6->is_nullable, 0, 'Field cannot be null' );
341
342 my $f7 = shift @fields;
343 is( $f7->name, 'store_id', 'Seventh field name is "store_id"' );
344 is( $f7->data_type, 'varchar', 'Type is "varchar"' );
345 is( $f7->size, 255, 'Size is "255"' );
346 is( $f7->is_nullable, 0, 'Field cannot be null' );
347 is( $f7->is_foreign_key, 1, 'Field is a FK' );
348 my $fk_ref = $f7->foreign_key_reference;
349 isa_ok( $fk_ref, 'SQL::Translator::Schema::Constraint', 'FK' );
350 is( $fk_ref->reference_table, 'store', 'FK is to "store" table' );
351
352 my $f8 = shift @fields;
353 is( $f8->name, 'tax', 'Eighth field name is "tax"' );
354 is( $f8->data_type, 'decimal', 'Type is "decimal"' );
355 is( $f8->size, '8,2', 'Size is "8,2"' );
356
357 my $f9 = shift @fields;
358 is( $f9->name, 'shipping_charge', 'Ninth field name is "shipping_charge"' );
359 is( $f9->data_type, 'decimal', 'Type is "decimal"' );
360 is( $f9->size, '8,2', 'Size is "8,2"' );
361
362 my $f10 = shift @fields;
363 is( $f10->name, 'price_paid', 'Tenth field name is "price_paid"' );
364 is( $f10->data_type, 'decimal', 'Type is "decimal"' );
365 is( $f10->size, '8,2', 'Size is "8,2"' );
366
367 my @indices = $t1->get_indices;
368 is( scalar @indices, 4, 'Right number of indices (4)' );
369
370 my $i1 = shift @indices;
371 is( $i1->type, NORMAL, 'First index is normal' );
372 is( join(',', $i1->fields), 'status', 'Index is on "status"' );
373
374 my $i2 = shift @indices;
375 is( $i2->type, NORMAL, 'Second index is normal' );
aee4b66e 376 is( join(',', $i2->fields), 'billing_address_id',
2ab84c11 377 'Index is on "billing_address_id"' );
378
379 my $i3 = shift @indices;
380 is( $i3->type, NORMAL, 'Third index is normal' );
aee4b66e 381 is( join(',', $i3->fields), 'shipping_address_id',
2ab84c11 382 'Index is on "shipping_address_id"' );
383
384 my $i4 = shift @indices;
385 is( $i4->type, NORMAL, 'Third index is normal' );
aee4b66e 386 is( join(',', $i4->fields), 'member_id,store_id',
2ab84c11 387 'Index is on "member_id,store_id"' );
388
389 my @constraints = $t1->get_constraints;
390 is( scalar @constraints, 5, 'Right number of constraints (5)' );
391
392 my $c1 = shift @constraints;
393 is( $c1->type, PRIMARY_KEY, 'Constraint is a PK' );
394 is( join(',', $c1->fields), 'order_id', 'Constraint is on "order_id"' );
395
396 my $c2 = shift @constraints;
397 is( $c2->type, FOREIGN_KEY, 'Constraint is a FK' );
398 is( join(',', $c2->fields), 'status', 'Constraint is on "status"' );
399 is( $c2->reference_table, 'order_status', 'To table "order_status"' );
400 is( join(',', $c2->reference_fields), 'id', 'To field "id"' );
401
402 my $c3 = shift @constraints;
403 is( $c3->type, FOREIGN_KEY, 'Constraint is a FK' );
aee4b66e 404 is( join(',', $c3->fields), 'billing_address_id',
2ab84c11 405 'Constraint is on "billing_address_id"' );
406 is( $c3->reference_table, 'address', 'To table "address"' );
aee4b66e 407 is( join(',', $c3->reference_fields), 'address_id',
2ab84c11 408 'To field "address_id"' );
409
410 my $c4 = shift @constraints;
411 is( $c4->type, FOREIGN_KEY, 'Constraint is a FK' );
aee4b66e 412 is( join(',', $c4->fields), 'shipping_address_id',
2ab84c11 413 'Constraint is on "shipping_address_id"' );
414 is( $c4->reference_table, 'address', 'To table "address"' );
aee4b66e 415 is( join(',', $c4->reference_fields), 'address_id',
2ab84c11 416 'To field "address_id"' );
417
418 my $c5 = shift @constraints;
419 is( $c5->type, FOREIGN_KEY, 'Constraint is a FK' );
420 is( join(',', $c5->fields), 'store_id', 'Constraint is on "store_id"' );
421 is( $c5->reference_table, 'store', 'To table "store"' );
aee4b66e 422 is( join(',', map { $_ || '' } $c5->reference_fields), '',
c9ca0061 423 'No reference fields defined' );
2ab84c11 424
425 my $t2 = shift @tables;
426 is( $t2->name, 'address', 'Found "address" table' );
427
428 my @t2_fields = $t2->get_fields;
429 is( scalar @t2_fields, 8, 'Right number of fields (8)' );
251b6ff5 430}
13aec984 431
432# djh Tests for:
433# USE database ;
434# ALTER TABLE ADD FOREIGN KEY
435# trailing comma on last create definition
436# Ignoring INSERT statements
437#
438{
439 my $tr = SQL::Translator->new;
aee4b66e 440 my $data = parse($tr,
13aec984 441 q[
442 USE database_name;
443
444 CREATE TABLE one (
445 id integer NOT NULL auto_increment,
446 two_id integer NOT NULL auto_increment,
447 some_data text,
448 PRIMARY KEY (id),
449 INDEX (two_id),
450 ) TYPE=INNODB;
451
452 CREATE TABLE two (
453 id int NOT NULL auto_increment,
454 one_id int NOT NULL auto_increment,
455 some_data text,
456 PRIMARY KEY (id),
457 INDEX (one_id),
458 FOREIGN KEY (one_id) REFERENCES one (id),
459 ) TYPE=INNODB;
460
461 ALTER TABLE one ADD FOREIGN KEY (two_id) REFERENCES two (id);
462
306c3c97 463 INSERT absolutely *#! any old $£ ? rubbish, even "quoted; semi-what""sits";
13aec984 464 ]
465 ) or die $tr->error;
466
467 my $schema = $tr->schema;
468 is( $schema->is_valid, 1, 'Schema is valid' );
469 my $db_name = $schema->name;
470 is( $db_name, 'database_name', 'Database name extracted from USE' );
471 my @tables = $schema->get_tables;
472 is( scalar @tables, 2, 'Right number of tables (2)' );
473 my $table1 = shift @tables;
474 is( $table1->name, 'one', 'Found "one" table' );
475 my $table2 = shift @tables;
476 is( $table2->name, 'two', 'Found "two" table' );
477
478 my @constraints = $table1->get_constraints;
479 is(scalar @constraints, 2, 'Right number of constraints (2) on table one');
480
481 my $t1c1 = shift @constraints;
482 is( $t1c1->type, PRIMARY_KEY, 'Constraint is a PK' );
483 is( join(',', $t1c1->fields), 'id', 'Constraint is on "id"' );
484
485 my $t1c2 = shift @constraints;
486 is( $t1c2->type, FOREIGN_KEY, 'Constraint is a FK' );
487 is( join(',', $t1c2->fields), 'two_id', 'Constraint is on "two_id"' );
488 is( $t1c2->reference_table, 'two', 'To table "two"' );
489 is( join(',', $t1c2->reference_fields), 'id', 'To field "id"' );
490
491 @constraints = $table2->get_constraints;
492 is(scalar @constraints, 2, 'Right number of constraints (2) on table two');
493
494 my $t2c1 = shift @constraints;
495 is( $t2c1->type, PRIMARY_KEY, 'Constraint is a PK' );
496 is( join(',', $t2c1->fields), 'id', 'Constraint is on "id"' );
497
498 my $t2c2 = shift @constraints;
499 is( $t2c2->type, FOREIGN_KEY, 'Constraint is a FK' );
500 is( join(',', $t2c2->fields), 'one_id', 'Constraint is on "one_id"' );
501 is( $t2c2->reference_table, 'one', 'To table "one"' );
502 is( join(',', $t2c2->reference_fields), 'id', 'To field "id"' );
503}
504
b68bfdf0 505# cch Tests for:
506# comments like: /*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
507# char fields with character set and collate qualifiers
508# timestamp fields with on update qualifier
509# charset table option
510#
511{
e6c5fb6e 512 my $tr = SQL::Translator->new(parser_args => {mysql_parser_version => 50013});
aee4b66e 513 my $data = parse($tr,
b68bfdf0 514 q[
aee4b66e 515 DELIMITER ;;
3e5e5622 516 /*!40101 SET SQL_MODE=@OLD_SQL_MODE */;;
aee4b66e 517 /*!50003 CREATE */ /*!50017 DEFINER=`cmdomain`@`localhost` */
518 /*!50003 TRIGGER `acl_entry_insert` BEFORE INSERT ON `acl_entry`
519 FOR EACH ROW SET NEW.dateCreated = CONVERT_TZ(SYSDATE(),'SYSTEM','+0:00'),
520 NEW.dateModified = CONVERT_TZ(SYSDATE(),'SYSTEM','+0:00') */;;
b68bfdf0 521
aee4b66e 522 DELIMITER ;
b68bfdf0 523 CREATE TABLE one (
524 `op` varchar(255) character set latin1 collate latin1_bin default NULL,
0a2833d8 525 `last_modified` timestamp NOT NULL default Current_Timestamp on update CURRENT_TIMESTAMP,
526 `created_at` datetime NOT NULL Default CURRENT_TIMESTAMP(),
b68bfdf0 527 ) TYPE=INNODB DEFAULT CHARSET=latin1;
d31c185b 528
aee4b66e 529 /*!50001 CREATE ALGORITHM=UNDEFINED */
530 /*!50013 DEFINER=`cmdomain`@`localhost` SQL SECURITY DEFINER */
e6c5fb6e 531 /*!50014 DEFINER=`BOGUS` */
aee4b66e 532 /*! VIEW `vs_asset` AS
533 select `a`.`asset_id` AS `asset_id`,`a`.`fq_name` AS `fq_name`,
534 `cfgmgmt_mig`.`ap_extract_folder`(`a`.`fq_name`) AS `folder_name`,
535 `cfgmgmt_mig`.`ap_extract_asset`(`a`.`fq_name`) AS `asset_name`,
536 `a`.`annotation` AS `annotation`,`a`.`asset_type` AS `asset_type`,
537 `a`.`foreign_asset_id` AS `foreign_asset_id`,
538 `a`.`foreign_asset_id2` AS `foreign_asset_id2`,`a`.`dateCreated` AS `date_created`,
539 `a`.`dateModified` AS `date_modified`,`a`.`container_id` AS `container_id`,
540 `a`.`creator_id` AS `creator_id`,`a`.`modifier_id` AS `modifier_id`,
541 `m`.`user_id` AS `user_access`
542 from (`asset` `a` join `M_ACCESS_CONTROL` `m` on((`a`.`acl_id` = `m`.`acl_id`))) */;
543 DELIMITER ;;
544 /*!50001 CREATE */
545 /*! VIEW `vs_asset2` AS
546 select `a`.`asset_id` AS `asset_id`,`a`.`fq_name` AS `fq_name`,
547 `cfgmgmt_mig`.`ap_extract_folder`(`a`.`fq_name`) AS `folder_name`,
548 `cfgmgmt_mig`.`ap_extract_asset`(`a`.`fq_name`) AS `asset_name`,
549 `a`.`annotation` AS `annotation`,`a`.`asset_type` AS `asset_type`,
550 `a`.`foreign_asset_id` AS `foreign_asset_id`,
551 `a`.`foreign_asset_id2` AS `foreign_asset_id2`,`a`.`dateCreated` AS `date_created`,
552 `a`.`dateModified` AS `date_modified`,`a`.`container_id` AS `container_id`,
553 `a`.`creator_id` AS `creator_id`,`a`.`modifier_id` AS `modifier_id`,
554 `m`.`user_id` AS `user_access`
555 from (`asset` `a` join `M_ACCESS_CONTROL` `m` on((`a`.`acl_id` = `m`.`acl_id`))) */;
556 DELIMITER ;;
557 /*!50001 CREATE OR REPLACE */
558 /*! VIEW `vs_asset3` AS
559 select `a`.`asset_id` AS `asset_id`,`a`.`fq_name` AS `fq_name`,
560 `cfgmgmt_mig`.`ap_extract_folder`(`a`.`fq_name`) AS `folder_name`,
561 `cfgmgmt_mig`.`ap_extract_asset`(`a`.`fq_name`) AS `asset_name`,
562 `a`.`annotation` AS `annotation`,`a`.`asset_type` AS `asset_type`,
563 `a`.`foreign_asset_id` AS `foreign_asset_id`,
564 `a`.`foreign_asset_id2` AS `foreign_asset_id2`,`a`.`dateCreated` AS `date_created`,
565 `a`.`dateModified` AS `date_modified`,`a`.`container_id` AS `container_id`,
566 `a`.`creator_id` AS `creator_id`,`a`.`modifier_id` AS `modifier_id`,
567 `m`.`user_id` AS `user_access`
568 from (`asset` `a` join `M_ACCESS_CONTROL` `m` on((`a`.`acl_id` = `m`.`acl_id`))) */;
569 DELIMITER ;;
570 /*!50003 CREATE*/ /*!50020 DEFINER=`cmdomain`@`localhost`*/ /*!50003 FUNCTION `ap_from_millitime_nullable`( millis_since_1970 BIGINT ) RETURNS timestamp
571 DETERMINISTIC
572 BEGIN
573 DECLARE rval TIMESTAMP;
574 IF ( millis_since_1970 = 0 )
575 THEN
576 SET rval = NULL;
577 ELSE
578 SET rval = FROM_UNIXTIME( millis_since_1970 / 1000 );
579 END IF;
580 RETURN rval;
581 END */;;
582 /*!50003 CREATE*/ /*!50020 DEFINER=`cmdomain`@`localhost`*/ /*!50003 PROCEDURE `sp_update_security_acl`(IN t_acl_id INTEGER)
583 BEGIN
584 DECLARE hasMoreRows BOOL DEFAULT TRUE;
585 DECLARE t_group_id INT;
586 DECLARE t_user_id INT ;
587 DECLARE t_user_name VARCHAR (512) ;
588 DECLARE t_message VARCHAR (512) ;
589
590 DROP TABLE IF EXISTS group_acl;
591 DROP TABLE IF EXISTS user_group;
592 DELETE FROM M_ACCESS_CONTROL WHERE acl_id = t_acl_id;
593
594 CREATE TEMPORARY TABLE group_acl SELECT DISTINCT p.id group_id, d.acl_id acl_id
595 FROM asset d, acl_entry e, alterpoint_principal p
596 WHERE d.acl_id = e.acl
597 AND p.id = e.principal AND d.acl_id = t_acl_id;
598
599 CREATE TEMPORARY TABLE user_group SELECT a.id user_id, a.name user_name, c.id group_id
600 FROM alterpoint_principal a, groups_for_user b, alterpoint_principal c
601 WHERE a.id = b.user_ref AND b.elt = c.id;
602
603 INSERT INTO M_ACCESS_CONTROL SELECT DISTINCT group_acl.group_id, group_acl.acl_id, user_group.user_id, user_group.user_name
604 FROM group_acl, user_group
605 WHERE group_acl.group_id = user_group.group_id ;
606 END */;;
b68bfdf0 607 ]
608 ) or die $tr->error;
609
610 my $schema = $tr->schema;
611 is( $schema->is_valid, 1, 'Schema is valid' );
612 my @tables = $schema->get_tables;
613 is( scalar @tables, 1, 'Right number of tables (1)' );
614 my $table1 = shift @tables;
615 is( $table1->name, 'one', 'Found "one" table' );
616
617 my @fields = $table1->get_fields;
0a2833d8 618 is(scalar @fields, 3, 'Right number of fields (3) on table one');
b68bfdf0 619 my $tableTypeFound = 0;
620 my $charsetFound = 0;
aee4b66e 621 for my $t1_option_ref ( $table1->options ) {
622 my($key, $value) = %{$t1_option_ref};
623 if ( $key eq 'TYPE' ) {
624 is($value, 'INNODB', 'Table has right table type option' );
625 $tableTypeFound = 1;
626 } elsif ( $key eq 'CHARACTER SET' ) {
627 is($value, 'latin1', 'Table has right character set option' );
628 $charsetFound = 1;
629 }
630 }
631 fail('Table did not have a type option') unless $tableTypeFound;
632 fail('Table did not have a character set option') unless $charsetFound;
b68bfdf0 633
634 my $t1f1 = shift @fields;
635 is( $t1f1->data_type, 'varchar', 'Field is a varchar' );
636 is( $t1f1->size, 255, 'Field is right size' );
637 is( $t1f1->extra('character set'), 'latin1', 'Field has right character set qualifier' );
638 is( $t1f1->extra('collate'), 'latin1_bin', 'Field has right collate qualifier' );
639 is( $t1f1->default_value, 'NULL', 'Field has right default value' );
640
641 my $t1f2 = shift @fields;
642 is( $t1f2->data_type, 'timestamp', 'Field is a timestamp' );
643 ok( !$t1f2->is_nullable, 'Field is not nullable' );
6d80a120 644 is_deeply(
645 $t1f2->default_value,
646 \'CURRENT_TIMESTAMP',
aee4b66e 647 'Field has right default value'
6d80a120 648 );
0a2833d8 649 is_deeply( $t1f2->extra('on update'), \'CURRENT_TIMESTAMP', 'Field has right on update qualifier' );
650
651 my $t1f3 = shift @fields;
652 is( $t1f3->data_type, 'datetime', 'Field is a datetime' );
653 ok( !$t1f3->is_nullable, 'Field is not nullable' );
654 is_deeply(
655 $t1f3->default_value,
656 \'CURRENT_TIMESTAMP',
657 'Field has right default value'
658 );
3ebe2ce5 659
d31c185b 660 my @views = $schema->get_views;
22b9814a 661 is( scalar @views, 3, 'Right number of views (3)' );
3ebe2ce5 662
663 my ($view1, $view2, $view3) = @views;
d31c185b 664 is( $view1->name, 'vs_asset', 'Found "vs_asset" view' );
22b9814a 665 is( $view2->name, 'vs_asset2', 'Found "vs_asset2" view' );
666 is( $view3->name, 'vs_asset3', 'Found "vs_asset3" view' );
3ebe2ce5 667 like($view1->sql, qr/vs_asset/, "Detected view vs_asset");
aa4301a7 668
669 # KYC - commenting this out as I don't understand why this string
670 # should /not/ be detected when it is in the SQL - 2/28/12
671 # like($view1->sql, qr/cfgmgmt_mig/, "Did not detect cfgmgmt_mig");
672
673 is( join(',', $view1->fields),
674 join(',', qw[ asset_id fq_name folder_name asset_name annotation
675 asset_type foreign_asset_id foreign_asset_id2 date_created
676 date_modified container_id creator_id modifier_id user_access
677 ] ),
678 'First view has correct fields'
679 );
3ebe2ce5 680
e6c5fb6e 681 my @options = $view1->options;
682
683 is_deeply(
684 \@options,
685 [
686 'ALGORITHM=UNDEFINED',
687 'DEFINER=`cmdomain`@`localhost`',
688 'SQL SECURITY DEFINER',
689 ],
690 'Only version 50013 options parsed',
691 );
692
d31c185b 693 my @procs = $schema->get_procedures;
694 is( scalar @procs, 2, 'Right number of procedures (2)' );
695 my $proc1 = shift @procs;
696 is( $proc1->name, 'ap_from_millitime_nullable', 'Found "ap_from_millitime_nullable" procedure' );
aee4b66e 697 like($proc1->sql, qr/CREATE FUNCTION ap_from_millitime_nullable/, "Detected procedure ap_from_millitime_nullable");
d31c185b 698 my $proc2 = shift @procs;
699 is( $proc2->name, 'sp_update_security_acl', 'Found "sp_update_security_acl" procedure' );
aee4b66e 700 like($proc2->sql, qr/CREATE PROCEDURE sp_update_security_acl/, "Detected procedure sp_update_security_acl");
b68bfdf0 701}
702
a7f49dfb 703# Tests for collate table option
704{
705 my $tr = SQL::Translator->new(parser_args => {mysql_parser_version => 50003});
aee4b66e 706 my $data = parse($tr,
a7f49dfb 707 q[
bb4c66d1 708 CREATE TABLE test ( id int ) DEFAULT CHARACTER SET latin1 COLLATE latin1_bin;
aee4b66e 709 ] );
4d438549 710
a7f49dfb 711 my $schema = $tr->schema;
712 is( $schema->is_valid, 1, 'Schema is valid' );
713 my @tables = $schema->get_tables;
714 is( scalar @tables, 1, 'Right number of tables (1)' );
715 my $table1 = shift @tables;
716 is( $table1->name, 'test', 'Found "test" table' );
717
718
719 my $collate = "Not found!";
bb4c66d1 720 my $charset = "Not found!";
a7f49dfb 721 for my $t1_option_ref ( $table1->options ) {
722 my($key, $value) = %{$t1_option_ref};
bb4c66d1 723 $collate = $value if $key eq 'COLLATE';
724 $charset = $value if $key eq 'CHARACTER SET';
a7f49dfb 725 }
726 is($collate, 'latin1_bin', "Collate found");
bb4c66d1 727 is($charset, 'latin1', "Character set found");
a7f49dfb 728}
5d666b31 729
730# Test the mysql version parser (probably needs to migrate to t/utils.t)
731my $parse_as = {
732 perl => {
733 '3.23.2' => 3.023002,
734 '4' => 4.000000,
735 '50003' => 5.000003,
736 '5.01.0' => 5.001000,
737 '5.1' => 5.001000,
738 },
739 mysql => {
740 '3.23.2' => 32302,
741 '4' => 40000,
742 '50003' => 50003,
743 '5.01.0' => 50100,
744 '5.1' => 50100,
745 },
746};
747
748for my $target (keys %$parse_as) {
749 for my $str (keys %{$parse_as->{$target}}) {
750 cmp_ok (
751 SQL::Translator::Utils::parse_mysql_version ($str, $target),
752 '==',
753 $parse_as->{$target}{$str},
754 "'$str' parsed as $target version '$parse_as->{$target}{$str}'",
755 );
756 }
757}
758
759eval { SQL::Translator::Utils::parse_mysql_version ('bogus5.1') };
760ok ($@, 'Exception thrown on invalid version string');
9a96648f 761
762{
763 my $tr = SQL::Translator->new;
764 my $data = q|create table merge_example (
765 id int(11) NOT NULL auto_increment,
766 shape_field geometry NOT NULL,
767 PRIMARY KEY (id),
768 SPATIAL KEY shape_field (shape_field)
769 ) ENGINE=MRG_MyISAM UNION=(`sometable_0`,`sometable_1`,`sometable_2`);|;
770
771 my $val = parse($tr, $data);
772 my $schema = $tr->schema;
773 is( $schema->is_valid, 1, 'Schema is valid' );
774 my @tables = $schema->get_tables;
775 is( scalar @tables, 1, 'Right number of tables (1)' );
776 my $table = shift @tables;
777 is( $table->name, 'merge_example', 'Found "merge_example" table' );
778
779 my $tableTypeFound = 0;
780 my $unionFound = 0;
781 for my $t_option_ref ( $table->options ) {
782 my($key, $value) = %{$t_option_ref};
783 if ( $key eq 'ENGINE' ) {
784 is($value, 'MRG_MyISAM', 'Table has right table engine option' );
785 $tableTypeFound = 1;
786 } elsif ( $key eq 'UNION' ) {
787 is_deeply($value, [ 'sometable_0','sometable_1','sometable_2' ],
788 "UNION option has correct set");
789 $unionFound = 1;
790 }
791 }
792
793 fail('Table did not have a type option') unless $tableTypeFound;
794 fail('Table did not have a union option') unless $unionFound;
795
796 my @fields = $table->get_fields;
797 is( scalar @fields, 2, 'Right number of fields (2)' );
798 my $f1 = shift @fields;
799 my $f2 = shift @fields;
800 is( $f1->name, 'id', 'First field name is "id"' );
801 is( $f1->data_type, 'int', 'Type is "int"' );
802 is( $f1->size, 11, 'Size is "11"' );
803 is( $f1->is_nullable, 0, 'Field cannot be null' );
804 is( $f1->is_primary_key, 1, 'Field is PK' );
805
806 is( $f2->name, 'shape_field', 'Second field name is "shape_field"' );
807 is( $f2->data_type, 'geometry', 'Type is "geometry"' );
808 is( $f2->is_nullable, 0, 'Field cannot be null' );
809 is( $f2->is_primary_key, 0, 'Field is not PK' );
810
811 my @indices = $table->get_indices;
812 is( scalar @indices, 1, 'Right number of indices (1)' );
813 my $i1 = shift @indices;
814 is( $i1->name, 'shape_field', 'No name on index' );
815 is( $i1->type, SPATIAL, 'Spatial index' );
816
817 my @constraints = $table->get_constraints;
818 is( scalar @constraints, 1, 'Right number of constraints (1)' );
819 my $c = shift @constraints;
820 is( $c->type, PRIMARY_KEY, 'Constraint is a PK' );
821 is( join(',', $c->fields), 'id', 'Constraint is on "id"' );
822}
47666977 823
824{
825 my @data = (
826 q|create table quote (
827 id int(11) NOT NULL auto_increment,
828 PRIMARY KEY (id)
829 ) ENGINE="innodb";|,
830 q|create table quote (
831 id int(11) NOT NULL auto_increment,
832 PRIMARY KEY (id)
833 ) ENGINE='innodb';|,
834 q|create table quote (
835 id int(11) NOT NULL auto_increment,
836 PRIMARY KEY (id)
837 ) ENGINE=innodb;|,
838 );
839 for my $data (@data) {
840 my $tr = SQL::Translator->new;
841
842 my $val = parse($tr, $data);
843 my $schema = $tr->schema;
844 is( $schema->is_valid, 1, 'Schema is valid' );
845 my @tables = $schema->get_tables;
846 is( scalar @tables, 1, 'Right number of tables (1)' );
847 my $table = shift @tables;
848 is( $table->name, 'quote', 'Found "quote" table' );
849
850 my $tableTypeFound = 0;
851 for my $t_option_ref ( $table->options ) {
852 my($key, $value) = %{$t_option_ref};
853 if ( $key eq 'ENGINE' ) {
854 is($value, 'innodb', 'Table has right table engine option' );
855 $tableTypeFound = 1;
856 }
857 }
858
859 fail('Table did not have a type option') unless $tableTypeFound;
860
861 my @fields = $table->get_fields;
862 my $f1 = shift @fields;
863 is( $f1->name, 'id', 'First field name is "id"' );
864 is( $f1->data_type, 'int', 'Type is "int"' );
865 is( $f1->size, 11, 'Size is "11"' );
866 is( $f1->is_nullable, 0, 'Field cannot be null' );
867 is( $f1->is_primary_key, 1, 'Field is PK' );
868 }
869}
870
8b075c9f 871{
872 my $tr = SQL::Translator->new;
873 my $data = q|create table "sessions" (
874 id char(32) not null default '0' primary key,
875 ssn varchar(12) NOT NULL default 'test single quotes like in you''re',
876 user varchar(20) NOT NULL default 'test single quotes escaped like you\'re',
34248db8 877 key using btree (ssn)
8b075c9f 878 );|;
879
880 my $val = parse($tr, $data);
881 my $schema = $tr->schema;
882 is( $schema->is_valid, 1, 'Schema is valid' );
883 my @tables = $schema->get_tables;
884 is( scalar @tables, 1, 'Right number of tables (1)' );
885 my $table = shift @tables;
886 is( $table->name, 'sessions', 'Found "sessions" table' );
887
888 my @fields = $table->get_fields;
889 is( scalar @fields, 3, 'Right number of fields (3)' );
890 my $f1 = shift @fields;
891 my $f2 = shift @fields;
892 my $f3 = shift @fields;
893 is( $f1->name, 'id', 'First field name is "id"' );
894 is( $f1->data_type, 'char', 'Type is "char"' );
895 is( $f1->size, 32, 'Size is "32"' );
896 is( $f1->is_nullable, 0, 'Field cannot be null' );
897 is( $f1->default_value, '0', 'Default value is "0"' );
898 is( $f1->is_primary_key, 1, 'Field is PK' );
899
900 is( $f2->name, 'ssn', 'Second field name is "ssn"' );
901 is( $f2->data_type, 'varchar', 'Type is "varchar"' );
902 is( $f2->size, 12, 'Size is "12"' );
903 is( $f2->is_nullable, 0, 'Field can not be null' );
aaea005b 904 is( $f2->default_value, "test single quotes like in you're", "Single quote in default value is unescaped properly" );
8b075c9f 905 is( $f2->is_primary_key, 0, 'Field is not PK' );
906
907 # this is more of a sanity test because the original sqlt regex for default looked for an escaped quote represented as \'
aee4b66e 908 # however in mysql 5.x (and probably other previous versions) still actually outputs that as ''
8b075c9f 909 is( $f3->name, 'user', 'Second field name is "user"' );
910 is( $f3->data_type, 'varchar', 'Type is "varchar"' );
911 is( $f3->size, 20, 'Size is "20"' );
912 is( $f3->is_nullable, 0, 'Field can not be null' );
aaea005b 913 is( $f3->default_value, "test single quotes escaped like you're", "Single quote in default value is unescaped properly" );
8b075c9f 914 is( $f3->is_primary_key, 0, 'Field is not PK' );
915}
34248db8 916
917{
918 # silence PR::D from spewing on STDERR
bdf60588 919 local $::RD_ERRORS = 0;
920 local $::RD_WARN = 0;
921 local $::RD_HINT = 0;
34248db8 922 my $tr = SQL::Translator->new;
923 my $data = q|create table "sessions" (
924 id char(32) not null default,
925 ssn varchar(12) NOT NULL default 'test single quotes like in you''re',
926 user varchar(20) NOT NULL default 'test single quotes escaped like you\'re',
927 key using btree (ssn)
928 );|;
929
930 my $val= parse($tr,$data);
931 ok ($tr->error =~ /Parse failed\./, 'Parse failed error without default value');
932}
933
934{
935 # make sure empty string default value still works
936 my $tr = SQL::Translator->new;
937 my $data = q|create table "sessions" (
938 id char(32) not null DEFAULT '',
939 ssn varchar(12) NOT NULL default "",
940 key using btree (ssn)
941 );|;
942 my $val= parse($tr,$data);
943
944 my @fields = $tr->schema->get_table('sessions')->get_fields;
945 is (scalar @fields, 2, 'Both fields parsed correctly');
946 for (@fields) {
947 my $def = $_->default_value;
948 ok( (defined $def and $def eq ''), "Defaults on field $_ correct" );
949 }
950}
d0a4031c 951
952{
953 # test rt70437 and rt71468
954 my $file = "$Bin/data/mysql/cashmusic_db.sql";
955 ok (-f $file,"File exists");
956 my $tr = SQL::Translator->new( parser => 'MySQL');
957 ok ($tr->translate($file),'File translated');
958 ok (!$tr->error, 'no error');
959 ok (my $schema = $tr->schema, 'got schema');
960}
2c1e8cab 961
962done_testing;