introspect ON DELETE/UPDATE for SQL Anywhere
[dbsrgits/DBIx-Class-Schema-Loader.git] / t / 10_08sqlanywhere_common.t
CommitLineData
8793567f 1use strict;
5347f501 2use warnings;
c4a69b87 3use Test::More;
4use Test::Exception;
5use Try::Tiny;
6use File::Path 'rmtree';
7use DBIx::Class::Schema::Loader 'make_schema_at';
8use Scope::Guard ();
9
8793567f 10use lib qw(t/lib);
c4a69b87 11
8793567f 12use dbixcsl_common_tests;
c4a69b87 13use dbixcsl_test_dir '$tdir';
14
15use constant EXTRA_DUMP_DIR => "$tdir/sqlanywhere_extra_dump";
8793567f 16
17# The default max_cursor_count and max_statement_count settings of 50 are too
18# low to run this test.
8a64178e 19#
20# Setting them to zero is preferred.
8793567f 21
637a5785 22my $dbd_sqlanywhere_dsn = $ENV{DBICTEST_SQLANYWHERE_DSN} || '';
23my $dbd_sqlanywhere_user = $ENV{DBICTEST_SQLANYWHERE_USER} || '';
24my $dbd_sqlanywhere_password = $ENV{DBICTEST_SQLANYWHERE_PASS} || '';
5347f501 25
637a5785 26my $odbc_dsn = $ENV{DBICTEST_SQLANYWHERE_ODBC_DSN} || '';
27my $odbc_user = $ENV{DBICTEST_SQLANYWHERE_ODBC_USER} || '';
28my $odbc_password = $ENV{DBICTEST_SQLANYWHERE_ODBC_PASS} || '';
8793567f 29
c4a69b87 30my ($schema, $schemas_created); # for cleanup in END for extra tests
31
8793567f 32my $tester = dbixcsl_common_tests->new(
33 vendor => 'SQLAnywhere',
34 auto_inc_pk => 'INTEGER IDENTITY NOT NULL PRIMARY KEY',
5347f501 35 connect_info => [ ($dbd_sqlanywhere_dsn ? {
36 dsn => $dbd_sqlanywhere_dsn,
37 user => $dbd_sqlanywhere_user,
38 password => $dbd_sqlanywhere_password,
39 } : ()),
40 ($odbc_dsn ? {
41 dsn => $odbc_dsn,
42 user => $odbc_user,
43 password => $odbc_password,
44 } : ()),
45 ],
dd87d4c4 46 loader_options => { preserve_case => 1 },
4b5eca90 47 default_is_deferrable => 1,
48 default_on_clause => 'RESTRICT',
9dc968df 49 data_types => {
50 # http://infocenter.sybase.com/help/topic/com.sybase.help.sqlanywhere.11.0.1/dbreference_en11/rf-datatypes.html
51 #
52 # Numeric types
53 'bit' => { data_type => 'bit' },
54 'tinyint' => { data_type => 'tinyint' },
55 'smallint' => { data_type => 'smallint' },
56 'int' => { data_type => 'integer' },
57 'integer' => { data_type => 'integer' },
58 'bigint' => { data_type => 'bigint' },
dd87d4c4 59 'float' => { data_type => 'real' },
60 'real' => { data_type => 'real' },
9dc968df 61 'double' => { data_type => 'double precision' },
62 'double precision' =>
63 { data_type => 'double precision' },
64
dd87d4c4 65 'float(2)' => { data_type => 'real' },
66 'float(24)' => { data_type => 'real' },
9dc968df 67 'float(25)' => { data_type => 'double precision' },
68 'float(53)' => { data_type => 'double precision' },
69
70 # This test only works with the default precision and scale options.
71 #
72 # They are preserved even for the default values, because the defaults
73 # can be changed.
74 'decimal' => { data_type => 'decimal', size => [30,6] },
75 'dec' => { data_type => 'decimal', size => [30,6] },
76 'numeric' => { data_type => 'numeric', size => [30,6] },
77
78 'decimal(3)' => { data_type => 'decimal', size => [3,0] },
79 'dec(3)' => { data_type => 'decimal', size => [3,0] },
80 'numeric(3)' => { data_type => 'numeric', size => [3,0] },
81
82 'decimal(3,3)' => { data_type => 'decimal', size => [3,3] },
83 'dec(3,3)' => { data_type => 'decimal', size => [3,3] },
84 'numeric(3,3)' => { data_type => 'numeric', size => [3,3] },
85
86 'decimal(18,18)' => { data_type => 'decimal', size => [18,18] },
87 'dec(18,18)' => { data_type => 'decimal', size => [18,18] },
88 'numeric(18,18)' => { data_type => 'numeric', size => [18,18] },
89
90 # money types
91 'money' => { data_type => 'money' },
92 'smallmoney' => { data_type => 'smallmoney' },
93
94 # bit arrays
95 'long varbit' => { data_type => 'long varbit' },
96 'long bit varying'
97 => { data_type => 'long varbit' },
98 'varbit' => { data_type => 'varbit', size => 1 },
99 'varbit(20)' => { data_type => 'varbit', size => 20 },
100 'bit varying' => { data_type => 'varbit', size => 1 },
101 'bit varying(20)'
102 => { data_type => 'varbit', size => 20 },
103
104 # Date and Time Types
105 'date' => { data_type => 'date' },
106 'datetime' => { data_type => 'datetime' },
107 'smalldatetime'
108 => { data_type => 'smalldatetime' },
109 'timestamp' => { data_type => 'timestamp' },
6e566cc4 110 # rewrite 'current timestamp' as 'current_timestamp'
111 'timestamp default current timestamp'
701cd3e3 112 => { data_type => 'timestamp', default_value => \'current_timestamp',
113 original => { default_value => \'current timestamp' } },
9dc968df 114 'time' => { data_type => 'time' },
115
116 # String Types
117 'char' => { data_type => 'char', size => 1 },
118 'char(11)' => { data_type => 'char', size => 11 },
119 'nchar' => { data_type => 'nchar', size => 1 },
120 'nchar(11)' => { data_type => 'nchar', size => 11 },
121 'varchar' => { data_type => 'varchar', size => 1 },
122 'varchar(20)' => { data_type => 'varchar', size => 20 },
123 'char varying(20)'
124 => { data_type => 'varchar', size => 20 },
125 'character varying(20)'
126 => { data_type => 'varchar', size => 20 },
127 'nvarchar(20)' => { data_type => 'nvarchar', size => 20 },
128 'xml' => { data_type => 'xml' },
129 'uniqueidentifierstr'
825c42a3 130 => { data_type => 'uniqueidentifierstr' },
9dc968df 131
132 # Binary types
133 'binary' => { data_type => 'binary', size => 1 },
134 'binary(20)' => { data_type => 'binary', size => 20 },
135 'varbinary' => { data_type => 'varbinary', size => 1 },
136 'varbinary(20)'=> { data_type => 'varbinary', size => 20 },
137 'uniqueidentifier'
825c42a3 138 => { data_type => 'uniqueidentifier' },
9dc968df 139
140 # Blob types
141 'long binary' => { data_type => 'long binary' },
142 'image' => { data_type => 'image' },
143 'long varchar' => { data_type => 'long varchar' },
144 'text' => { data_type => 'text' },
145 'long nvarchar'=> { data_type => 'long nvarchar' },
146 'ntext' => { data_type => 'ntext' },
147 },
c4a69b87 148 extra => {
4b5eca90 149 create => [
150 # 4 through 8 are used for the multi-schema tests
151 q{
152 create table sqlanywhere_loader_test9 (
153 id int identity not null primary key
154 )
155 },
156 q{
157 create table sqlanywhere_loader_test10 (
158 id int identity not null primary key,
159 nine_id int,
160 foreign key (nine_id) references sqlanywhere_loader_test9(id)
161 on delete cascade on update set null
162 )
163 },
164 ],
165 drop => [ qw/sqlanywhere_loader_test9 sqlanywhere_loader_test10/ ],
166 count => 4 + 30 * 2,
c4a69b87 167 run => sub {
168 SKIP: {
169 $schema = $_[0];
170 my $self = $_[3];
171
4b5eca90 172 # test on delete/update fk clause introspection
173 ok ((my $rel_info = $schema->source('SqlanywhereLoaderTest10')->relationship_info('nine')),
174 'got rel info');
175
176 is $rel_info->{attrs}{on_delete}, 'CASCADE',
177 'ON DELETE clause introspected correctly';
178
179 is $rel_info->{attrs}{on_update}, 'SET NULL',
180 'ON UPDATE clause introspected correctly';
181
182 is $rel_info->{attrs}{is_deferrable}, 1,
183 'is_deferrable defaults to 1';
184
c4a69b87 185 my $connect_info = [@$self{qw/dsn user password/}];
186
187 my $dbh = $schema->storage->dbh;
188
189 try {
190 $dbh->do("CREATE USER dbicsl_test1 identified by 'dbicsl'");
191 }
192 catch {
193 $schemas_created = 0;
5975bbe6 194 skip "no CREATE USER privileges", 30 * 2;
c4a69b87 195 };
196
197 $dbh->do(<<"EOF");
198 CREATE TABLE dbicsl_test1.sqlanywhere_loader_test4 (
199 id INT IDENTITY NOT NULL PRIMARY KEY,
200 value VARCHAR(100)
201 )
202EOF
203 $dbh->do(<<"EOF");
204 CREATE TABLE dbicsl_test1.sqlanywhere_loader_test5 (
205 id INT IDENTITY NOT NULL PRIMARY KEY,
206 value VARCHAR(100),
5975bbe6 207 four_id INTEGER NOT NULL,
208 CONSTRAINT loader_test5_uniq UNIQUE (four_id),
c4a69b87 209 FOREIGN KEY (four_id) REFERENCES dbicsl_test1.sqlanywhere_loader_test4 (id)
210 )
211EOF
212 $dbh->do("CREATE USER dbicsl_test2 identified by 'dbicsl'");
213 $dbh->do(<<"EOF");
5975bbe6 214 CREATE TABLE dbicsl_test2.sqlanywhere_loader_test5 (
215 pk INT IDENTITY NOT NULL PRIMARY KEY,
216 value VARCHAR(100),
217 four_id INTEGER NOT NULL,
218 CONSTRAINT loader_test5_uniq UNIQUE (four_id),
219 FOREIGN KEY (four_id) REFERENCES dbicsl_test1.sqlanywhere_loader_test4 (id)
220 )
221EOF
222 $dbh->do(<<"EOF");
c4a69b87 223 CREATE TABLE dbicsl_test2.sqlanywhere_loader_test6 (
224 id INT IDENTITY NOT NULL PRIMARY KEY,
225 value VARCHAR(100),
226 sqlanywhere_loader_test4_id INTEGER,
227 FOREIGN KEY (sqlanywhere_loader_test4_id) REFERENCES dbicsl_test1.sqlanywhere_loader_test4 (id)
228 )
229EOF
230 $dbh->do(<<"EOF");
231 CREATE TABLE dbicsl_test2.sqlanywhere_loader_test7 (
232 id INT IDENTITY NOT NULL PRIMARY KEY,
233 value VARCHAR(100),
234 six_id INTEGER NOT NULL UNIQUE,
235 FOREIGN KEY (six_id) REFERENCES dbicsl_test2.sqlanywhere_loader_test6 (id)
236 )
237EOF
238 $dbh->do(<<"EOF");
239 CREATE TABLE dbicsl_test1.sqlanywhere_loader_test8 (
240 id INT IDENTITY NOT NULL PRIMARY KEY,
241 value VARCHAR(100),
242 sqlanywhere_loader_test7_id INTEGER,
243 FOREIGN KEY (sqlanywhere_loader_test7_id) REFERENCES dbicsl_test2.sqlanywhere_loader_test7 (id)
244 )
245EOF
246
247 $schemas_created = 1;
248
249 my $guard = Scope::Guard->new(\&extra_cleanup);
250
251 foreach my $db_schema (['dbicsl_test1', 'dbicsl_test2'], '%') {
252 lives_and {
253 rmtree EXTRA_DUMP_DIR;
254
255 my @warns;
256 local $SIG{__WARN__} = sub {
257 push @warns, $_[0] unless $_[0] =~ /\bcollides\b/;
258 };
259
260 make_schema_at(
261 'SQLAnywhereMultiSchema',
262 {
263 naming => 'current',
264 db_schema => $db_schema,
265 dump_directory => EXTRA_DUMP_DIR,
266 quiet => 1,
267 },
268 $connect_info,
269 );
270
271 diag join "\n", @warns if @warns;
272
273 is @warns, 0;
274 } 'dumped schema for dbicsl_test1 and dbicsl_test2 schemas with no warnings';
275
276 my ($test_schema, $rsrc, $rs, $row, %uniqs, $rel_info);
277
278 lives_and {
279 ok $test_schema = SQLAnywhereMultiSchema->connect(@$connect_info);
280 } 'connected test schema';
281
282 lives_and {
4c2e2ce9 283 ok $rsrc = $test_schema->source('SqlanywhereLoaderTest4');
c4a69b87 284 } 'got source for table in schema one';
285
286 is try { $rsrc->column_info('id')->{is_auto_increment} }, 1,
287 'column in schema one';
288
289 is try { $rsrc->column_info('value')->{data_type} }, 'varchar',
290 'column in schema one';
291
292 is try { $rsrc->column_info('value')->{size} }, 100,
293 'column in schema one';
294
295 lives_and {
4c2e2ce9 296 ok $rs = $test_schema->resultset('SqlanywhereLoaderTest4');
c4a69b87 297 } 'got resultset for table in schema one';
298
299 lives_and {
300 ok $row = $rs->create({ value => 'foo' });
301 } 'executed SQL on table in schema one';
302
5975bbe6 303 $rel_info = try { $rsrc->relationship_info('dbicsl_test1_sqlanywhere_loader_test5') };
c4a69b87 304
305 is_deeply $rel_info->{cond}, {
306 'foreign.four_id' => 'self.id'
307 }, 'relationship in schema one';
9dc968df 308
c4a69b87 309 is $rel_info->{attrs}{accessor}, 'single',
310 'relationship in schema one';
311
312 is $rel_info->{attrs}{join_type}, 'LEFT',
313 'relationship in schema one';
314
315 lives_and {
5975bbe6 316 ok $rsrc = $test_schema->source('DbicslTest1SqlanywhereLoaderTest5');
c4a69b87 317 } 'got source for table in schema one';
318
319 %uniqs = try { $rsrc->unique_constraints };
320
321 is keys %uniqs, 2,
322 'got unique and primary constraint in schema one';
323
5975bbe6 324 delete $uniqs{primary};
325
326 is_deeply ((values %uniqs)[0], ['four_id'],
327 'correct unique constraint in schema one');
328
c4a69b87 329 lives_and {
4c2e2ce9 330 ok $rsrc = $test_schema->source('SqlanywhereLoaderTest6');
c4a69b87 331 } 'got source for table in schema two';
332
333 is try { $rsrc->column_info('id')->{is_auto_increment} }, 1,
334 'column in schema two introspected correctly';
335
336 is try { $rsrc->column_info('value')->{data_type} }, 'varchar',
337 'column in schema two introspected correctly';
338
339 is try { $rsrc->column_info('value')->{size} }, 100,
340 'column in schema two introspected correctly';
341
342 lives_and {
4c2e2ce9 343 ok $rs = $test_schema->resultset('SqlanywhereLoaderTest6');
c4a69b87 344 } 'got resultset for table in schema two';
345
346 lives_and {
347 ok $row = $rs->create({ value => 'foo' });
348 } 'executed SQL on table in schema two';
349
350 $rel_info = try { $rsrc->relationship_info('sqlanywhere_loader_test7') };
351
352 is_deeply $rel_info->{cond}, {
353 'foreign.six_id' => 'self.id'
354 }, 'relationship in schema two';
355
356 is $rel_info->{attrs}{accessor}, 'single',
357 'relationship in schema two';
358
359 is $rel_info->{attrs}{join_type}, 'LEFT',
360 'relationship in schema two';
361
362 lives_and {
4c2e2ce9 363 ok $rsrc = $test_schema->source('SqlanywhereLoaderTest7');
c4a69b87 364 } 'got source for table in schema two';
365
366 %uniqs = try { $rsrc->unique_constraints };
367
368 is keys %uniqs, 2,
369 'got unique and primary constraint in schema two';
370
5975bbe6 371 delete $uniqs{primary};
372
373 is_deeply ((values %uniqs)[0], ['six_id'],
374 'correct unique constraint in schema two');
375
c4a69b87 376 lives_and {
4c2e2ce9 377 ok $test_schema->source('SqlanywhereLoaderTest6')
c4a69b87 378 ->has_relationship('sqlanywhere_loader_test4');
379 } 'cross-schema relationship in multi-db_schema';
380
381 lives_and {
4c2e2ce9 382 ok $test_schema->source('SqlanywhereLoaderTest4')
c4a69b87 383 ->has_relationship('sqlanywhere_loader_test6s');
384 } 'cross-schema relationship in multi-db_schema';
385
386 lives_and {
4c2e2ce9 387 ok $test_schema->source('SqlanywhereLoaderTest8')
c4a69b87 388 ->has_relationship('sqlanywhere_loader_test7');
389 } 'cross-schema relationship in multi-db_schema';
390
391 lives_and {
4c2e2ce9 392 ok $test_schema->source('SqlanywhereLoaderTest7')
c4a69b87 393 ->has_relationship('sqlanywhere_loader_test8s');
394 } 'cross-schema relationship in multi-db_schema';
395 }
396 }
397 },
398 },
8793567f 399);
400
5347f501 401if (not ($dbd_sqlanywhere_dsn || $odbc_dsn)) {
637a5785 402 $tester->skip_tests('You need to set the DBICTEST_SQLANYWHERE_DSN, _USER and _PASS and/or the DBICTEST_SQLANYWHERE_ODBC_DSN, _USER and _PASS environment variables');
8793567f 403}
404else {
405 $tester->run_tests();
406}
c4a69b87 407
408sub extra_cleanup {
409 if (not $ENV{SCHEMA_LOADER_TESTS_NOCLEANUP}) {
410 if ($schemas_created && (my $dbh = try { $schema->storage->dbh })) {
411 foreach my $table ('dbicsl_test1.sqlanywhere_loader_test8',
412 'dbicsl_test2.sqlanywhere_loader_test7',
413 'dbicsl_test2.sqlanywhere_loader_test6',
5975bbe6 414 'dbicsl_test2.sqlanywhere_loader_test5',
c4a69b87 415 'dbicsl_test1.sqlanywhere_loader_test5',
416 'dbicsl_test1.sqlanywhere_loader_test4') {
417 try {
418 $dbh->do("DROP TABLE $table");
419 }
420 catch {
421 diag "Error dropping table: $_";
422 };
423 }
424
425 foreach my $db_schema (qw/dbicsl_test1 dbicsl_test2/) {
426 try {
427 $dbh->do("DROP USER $db_schema");
428 }
429 catch {
430 diag "Error dropping test user $db_schema: $_";
431 };
432 }
433 }
434 rmtree EXTRA_DUMP_DIR;
435 }
436}
701cd3e3 437# vim:et sts=4 sw=4 tw=0: