Attempt to fix 'Attempt to free unreferenced scalar' on 5.8
[dbsrgits/DBIx-Class-Schema-Loader.git] / t / 10_06sybase_common.t
1 use DBIx::Class::Schema::Loader::Optional::Dependencies
2     -skip_all_without => 'test_rdbms_ase';
3
4 use strict;
5 use warnings;
6 use Test::More;
7 use Test::Exception;
8 use Try::Tiny;
9 use File::Path 'rmtree';
10 use DBIx::Class::Schema::Loader 'make_schema_at';
11 use DBIx::Class::Schema::Loader::Utils qw/sigwarn_silencer/;
12 use DBI ();
13
14 use lib qw(t/lib);
15
16 use dbixcsl_common_tests ();
17 use dbixcsl_test_dir '$tdir';
18
19 use constant EXTRA_DUMP_DIR => "$tdir/sybase_extra_dump";
20
21 my $dsn      = $ENV{DBICTEST_SYBASE_DSN} || '';
22 my $user     = $ENV{DBICTEST_SYBASE_USER} || '';
23 my $password = $ENV{DBICTEST_SYBASE_PASS} || '';
24
25 BEGIN { $ENV{DBIC_SYBASE_FREETDS_NOWARN} = 1 }
26
27 my ($schema, $databases_created); # for cleanup in END for extra tests
28
29 dbixcsl_common_tests->new(
30     vendor      => 'sybase',
31     auto_inc_pk => 'INTEGER IDENTITY NOT NULL PRIMARY KEY',
32     default_function     => 'getdate()',
33     default_function_def => 'AS getdate()',
34     dsn         => $dsn,
35     user        => $user,
36     password    => $password,
37     data_types  => {
38         # http://ispirer.com/wiki/sqlways/sybase/data-types
39         #
40         # Numeric Types
41         'integer identity' => { data_type => 'integer', is_auto_increment => 1 },
42         int      => { data_type => 'integer' },
43         integer  => { data_type => 'integer' },
44         bigint   => { data_type => 'bigint' },
45         smallint => { data_type => 'smallint' },
46         tinyint  => { data_type => 'tinyint' },
47         'double precision' => { data_type => 'double precision' },
48         real           => { data_type => 'real' },
49         float          => { data_type => 'double precision' },
50         'float(14)'    => { data_type => 'real' },
51         'float(15)'    => { data_type => 'real' },
52         'float(16)'    => { data_type => 'double precision' },
53         'float(48)'    => { data_type => 'double precision' },
54         'numeric(6,3)' => { data_type => 'numeric', size => [6,3] },
55         'decimal(6,3)' => { data_type => 'numeric', size => [6,3] },
56         numeric        => { data_type => 'numeric' },
57         decimal        => { data_type => 'numeric' },
58         bit            => { data_type => 'bit' },
59
60         # Money Types
61         money          => { data_type => 'money' },
62         smallmoney     => { data_type => 'smallmoney' },
63
64         # Computed Column
65         'AS getdate()'     => { data_type => undef, inflate_datetime => 1, default_value => \'getdate()' },
66
67         # Blob Types
68         text     => { data_type => 'text' },
69         unitext  => { data_type => 'unitext' },
70         image    => { data_type => 'image' },
71
72         # DateTime Types
73         date     => { data_type => 'date' },
74         time     => { data_type => 'time' },
75         datetime => { data_type => 'datetime' },
76         smalldatetime  => { data_type => 'smalldatetime' },
77
78         # Timestamp column
79         timestamp      => { data_type => 'timestamp', inflate_datetime => 0 },
80
81         # String Types
82         'char'         => { data_type => 'char', size => 1 },
83         'char(2)'      => { data_type => 'char', size => 2 },
84         'nchar'        => { data_type => 'nchar', size => 1 },
85         'nchar(2)'     => { data_type => 'nchar', size => 2 },
86         'unichar(2)'   => { data_type => 'unichar', size => 2 },
87         'varchar(2)'   => { data_type => 'varchar', size => 2 },
88         'nvarchar(2)'  => { data_type => 'nvarchar', size => 2 },
89         'univarchar(2)' => { data_type => 'univarchar', size => 2 },
90
91         # Binary Types
92         'binary'       => { data_type => 'binary', size => 1 },
93         'binary(2)'    => { data_type => 'binary', size => 2 },
94         'varbinary(2)' => { data_type => 'varbinary', size => 2 },
95     },
96     # test that named constraints aren't picked up as tables (I can't reproduce this on my machine)
97     failtrigger_warnings => [ qr/^Bad table or view 'sybase_loader_test2_ref_slt1'/ ],
98     extra => {
99         create => [
100             q{
101                 CREATE TABLE sybase_loader_test1 (
102                     id int identity primary key
103                 )
104             },
105             q{
106                 CREATE TABLE sybase_loader_test2 (
107                     id int identity primary key,
108                     sybase_loader_test1_id int,
109                     CONSTRAINT sybase_loader_test2_ref_slt1 FOREIGN KEY (sybase_loader_test1_id) REFERENCES sybase_loader_test1 (id)
110                 )
111             },
112         ],
113         drop => [ qw/sybase_loader_test1 sybase_loader_test2/ ],
114         count => 30 * 4,
115         run => sub {
116             $schema = shift;
117
118             SKIP: {
119                 my $dbh = $schema->storage->dbh;
120
121                 try {
122                     $dbh->do('USE master');
123                 }
124                 catch {
125                     skip "these tests require the sysadmin role", 30 * 4;
126                 };
127
128                 try {
129                     $dbh->do('CREATE DATABASE [dbicsl_test1]');
130                     $dbh->do('CREATE DATABASE [dbicsl_test2]');
131                 }
132                 catch {
133                     skip "cannot create databases: $_", 30 * 4;
134                 };
135
136                 try {
137                     local $SIG{__WARN__} = sigwarn_silencer(
138                         qr/^Password correctly set\.$|^Account unlocked\.$|^New login created\.$|^New user added\.$/
139                     );
140
141                     $dbh->do("sp_addlogin dbicsl_user1, dbicsl, [dbicsl_test1]");
142                     $dbh->do("sp_addlogin dbicsl_user2, dbicsl, [dbicsl_test2]");
143
144                     $dbh->do("USE [dbicsl_test1]");
145                     $dbh->do("sp_adduser dbicsl_user1");
146                     $dbh->do("sp_adduser dbicsl_user2");
147                     $dbh->do("GRANT ALL TO dbicsl_user1");
148                     $dbh->do("GRANT ALL TO dbicsl_user2");
149
150                     $dbh->do("USE [dbicsl_test2]");
151                     $dbh->do("sp_adduser dbicsl_user2");
152                     $dbh->do("sp_adduser dbicsl_user1");
153                     $dbh->do("GRANT ALL TO dbicsl_user2");
154                     $dbh->do("GRANT ALL TO dbicsl_user1");
155                 }
156                 catch {
157                     skip "cannot add logins: $_", 30 * 4;
158                 };
159
160                 my ($dbh1, $dbh2);
161                 {
162                     local $SIG{__WARN__} = sigwarn_silencer(
163                         qr/can't change context/
164                     );
165                     $dbh1 = DBI->connect($dsn, 'dbicsl_user1', 'dbicsl', {
166                         RaiseError => 1,
167                         PrintError => 0,
168                     });
169                     $dbh1->do('USE [dbicsl_test1]');
170
171                     $dbh2 = DBI->connect($dsn, 'dbicsl_user2', 'dbicsl', {
172                         RaiseError => 1,
173                         PrintError => 0,
174                     });
175                     $dbh2->do('USE [dbicsl_test2]');
176                 }
177
178                 $dbh1->do(<<"EOF");
179                     CREATE TABLE sybase_loader_test4 (
180                         id INT IDENTITY PRIMARY KEY,
181                         value VARCHAR(100) NULL
182                     )
183 EOF
184                 $dbh1->do('GRANT ALL ON sybase_loader_test4 TO dbicsl_user2');
185                 $dbh1->do(<<"EOF");
186                     CREATE TABLE sybase_loader_test5 (
187                         id INT IDENTITY PRIMARY KEY,
188                         value VARCHAR(100) NULL,
189                         four_id INTEGER,
190                         CONSTRAINT loader_test5_uniq UNIQUE (four_id),
191                         FOREIGN KEY (four_id) REFERENCES sybase_loader_test4 (id)
192                     )
193 EOF
194                 $dbh2->do(<<"EOF");
195                     CREATE TABLE sybase_loader_test5 (
196                         pk INT IDENTITY PRIMARY KEY,
197                         value VARCHAR(100) NULL,
198                         four_id INTEGER,
199                         CONSTRAINT loader_test5_uniq UNIQUE (four_id),
200                         FOREIGN KEY (four_id) REFERENCES [dbicsl_test1].dbicsl_user1.sybase_loader_test4 (id)
201                     )
202 EOF
203                 $dbh2->do(<<"EOF");
204                     CREATE TABLE sybase_loader_test6 (
205                         id INT IDENTITY PRIMARY KEY,
206                         value VARCHAR(100) NULL,
207                         sybase_loader_test4_id INTEGER NULL,
208                         FOREIGN KEY (sybase_loader_test4_id) REFERENCES [dbicsl_test1].dbicsl_user1.sybase_loader_test4 (id)
209                     )
210 EOF
211                 $dbh2->do(<<"EOF");
212                     CREATE TABLE sybase_loader_test7 (
213                         id INT IDENTITY PRIMARY KEY,
214                         value VARCHAR(100) NULL,
215                         six_id INTEGER UNIQUE,
216                         FOREIGN KEY (six_id) REFERENCES sybase_loader_test6 (id)
217                     )
218 EOF
219                 $dbh2->do('GRANT ALL ON sybase_loader_test7 TO dbicsl_user1');
220                 $dbh1->do(<<"EOF");
221                     CREATE TABLE sybase_loader_test8 (
222                         id INT IDENTITY PRIMARY KEY,
223                         value VARCHAR(100) NULL,
224                         sybase_loader_test7_id INTEGER,
225                         FOREIGN KEY (sybase_loader_test7_id) REFERENCES [dbicsl_test2].dbicsl_user2.sybase_loader_test7 (id)
226                     )
227 EOF
228
229                 $databases_created = 1;
230
231                 foreach my $databases (['dbicsl_test1', 'dbicsl_test2'], '%') {
232                     foreach my $owners ([qw/dbicsl_user1 dbicsl_user2/], '%') {
233                         lives_and {
234                             rmtree EXTRA_DUMP_DIR;
235
236                             my @warns;
237                             local $SIG{__WARN__} = sub {
238                                 push @warns, $_[0] unless $_[0] =~ /\bcollides\b/
239                                     || $_[0] =~ /can't change context/;
240                             };
241
242                             my $database = $databases;
243
244                             $database = [ $database ] unless ref $database;
245
246                             my $db_schema = {};
247
248                             foreach my $db (@$database) {
249                                 $db_schema->{$db} = $owners;
250                             }
251
252                             make_schema_at(
253                                 'SybaseMultiSchema',
254                                 {
255                                     naming => 'current',
256                                     db_schema => $db_schema,
257                                     dump_directory => EXTRA_DUMP_DIR,
258                                     quiet => 1,
259                                 },
260                                 [ $dsn, $user, $password ],
261                             );
262
263                             SybaseMultiSchema->storage->disconnect;
264
265                             diag join "\n", @warns if @warns;
266
267                             is @warns, 0;
268                         } 'dumped schema for "dbicsl_test1" and "dbicsl_test2" databases with no warnings';
269
270                         my ($test_schema, $rsrc, $rs, $row, %uniqs, $rel_info);
271
272                         lives_and {
273                             ok $test_schema = SybaseMultiSchema->connect($dsn, $user, $password);
274                         } 'connected test schema';
275
276                         lives_and {
277                             ok $rsrc = $test_schema->source('SybaseLoaderTest4');
278                         } 'got source for table in database one';
279
280                         is try { $rsrc->column_info('id')->{is_auto_increment} }, 1,
281                             'column in database one';
282
283                         is try { $rsrc->column_info('value')->{data_type} }, 'varchar',
284                             'column in database one';
285
286                         is try { $rsrc->column_info('value')->{size} }, 100,
287                             'column in database one';
288
289                         lives_and {
290                             ok $rs = $test_schema->resultset('SybaseLoaderTest4');
291                         } 'got resultset for table in database one';
292
293                         lives_and {
294                             ok $row = $rs->create({ value => 'foo' });
295                         } 'executed SQL on table in database one';
296
297                         $rel_info = try { $rsrc->relationship_info('dbicsl_test1_sybase_loader_test5') };
298
299                         is_deeply $rel_info->{cond}, {
300                             'foreign.four_id' => 'self.id'
301                         }, 'relationship in database one';
302
303                         is $rel_info->{attrs}{accessor}, 'single',
304                             'relationship in database one';
305
306                         is $rel_info->{attrs}{join_type}, 'LEFT',
307                             'relationship in database one';
308
309                         lives_and {
310                             ok $rsrc = $test_schema->source('DbicslTest1SybaseLoaderTest5');
311                         } 'got source for table in database one';
312
313                         %uniqs = try { $rsrc->unique_constraints };
314
315                         is keys %uniqs, 2,
316                             'got unique and primary constraint in database one';
317
318                         delete $uniqs{primary};
319
320                         is_deeply ((values %uniqs)[0], ['four_id'],
321                             'correct unique constraint in database one');
322
323                         lives_and {
324                             ok $rsrc = $test_schema->source('SybaseLoaderTest6');
325                         } 'got source for table in database two';
326
327                         is try { $rsrc->column_info('id')->{is_auto_increment} }, 1,
328                             'column in database two introspected correctly';
329
330                         is try { $rsrc->column_info('value')->{data_type} }, 'varchar',
331                             'column in database two introspected correctly';
332
333                         is try { $rsrc->column_info('value')->{size} }, 100,
334                             'column in database two introspected correctly';
335
336                         lives_and {
337                             ok $rs = $test_schema->resultset('SybaseLoaderTest6');
338                         } 'got resultset for table in database two';
339
340                         lives_and {
341                             ok $row = $rs->create({ value => 'foo' });
342                         } 'executed SQL on table in database two';
343
344                         $rel_info = try { $rsrc->relationship_info('sybase_loader_test7') };
345
346                         is_deeply $rel_info->{cond}, {
347                             'foreign.six_id' => 'self.id'
348                         }, 'relationship in database two';
349
350                         is $rel_info->{attrs}{accessor}, 'single',
351                             'relationship in database two';
352
353                         is $rel_info->{attrs}{join_type}, 'LEFT',
354                             'relationship in database two';
355
356                         lives_and {
357                             ok $rsrc = $test_schema->source('SybaseLoaderTest7');
358                         } 'got source for table in database two';
359
360                         %uniqs = try { $rsrc->unique_constraints };
361
362                         is keys %uniqs, 2,
363                             'got unique and primary constraint in database two';
364
365                         delete $uniqs{primary};
366
367                         is_deeply ((values %uniqs)[0], ['six_id'],
368                             'correct unique constraint in database two');
369
370                         lives_and {
371                             ok $test_schema->source('SybaseLoaderTest6')
372                                 ->has_relationship('sybase_loader_test4');
373                         } 'cross-database relationship in multi database schema';
374
375                         lives_and {
376                             ok $test_schema->source('SybaseLoaderTest4')
377                                 ->has_relationship('sybase_loader_test6s');
378                         } 'cross-database relationship in multi database schema';
379
380                         lives_and {
381                             ok $test_schema->source('SybaseLoaderTest8')
382                                 ->has_relationship('sybase_loader_test7');
383                         } 'cross-database relationship in multi database schema';
384
385                         lives_and {
386                             ok $test_schema->source('SybaseLoaderTest7')
387                                 ->has_relationship('sybase_loader_test8s');
388                         } 'cross-database relationship in multi database schema';
389                     }
390                 }
391             }
392         },
393     },
394 )->run_tests();
395
396 END {
397     if (not $ENV{SCHEMA_LOADER_TESTS_NOCLEANUP}) {
398         rmtree EXTRA_DUMP_DIR;
399
400         if ($databases_created) {
401             my $dbh = $schema->storage->dbh;
402
403             $dbh->do('USE master');
404
405             local $dbh->{FetchHashKeyName} = 'NAME_lc';
406
407             my $sth = $dbh->prepare('sp_who');
408             $sth->execute;
409
410             while (my $row = $sth->fetchrow_hashref) {
411                 if ($row->{dbname} =~ /^dbicsl_test[12]\z/) {
412                     $dbh->do("kill $row->{spid}");
413                 }
414             }
415
416             foreach my $table ('[dbicsl_test1].dbicsl_user1.sybase_loader_test8',
417                                '[dbicsl_test2].dbicsl_user2.sybase_loader_test7',
418                                '[dbicsl_test2].dbicsl_user2.sybase_loader_test6',
419                                '[dbicsl_test2].dbicsl_user2.sybase_loader_test5',
420                                '[dbicsl_test1].dbicsl_user1.sybase_loader_test5',
421                                '[dbicsl_test1].dbicsl_user1.sybase_loader_test4') {
422                 try {
423                     $dbh->do("DROP TABLE $table");
424                 }
425                 catch {
426                     diag "Error dropping table $table: $_";
427                 };
428             }
429
430             foreach my $db (qw/dbicsl_test1 dbicsl_test2/) {
431                 try {
432                     $dbh->do("DROP DATABASE [$db]");
433                 }
434                 catch {
435                     diag "Error dropping test database $db: $_";
436                 };
437             }
438
439             foreach my $login (qw/dbicsl_user1 dbicsl_user2/) {
440                 try {
441                     local $SIG{__WARN__} = sigwarn_silencer(
442                         qr/^Account locked\.$|^Login dropped\.$/
443                     );
444
445                     $dbh->do("sp_droplogin $login");
446                 }
447                 catch {
448                     diag "Error dropping login $login: $_"
449                         unless /Incorrect syntax/;
450                 };
451             }
452         }
453     }
454 }
455 # vim:et sts=4 sw=4 tw=0: