Commit | Line | Data |
bc5afe55 |
1 | use strict; |
c4a69b87 |
2 | use warnings; |
3 | use Test::More; |
4 | use Test::Exception; |
5 | use Try::Tiny; |
6 | use File::Path 'rmtree'; |
4fb2971c |
7 | use DBIx::Class::Optional::Dependencies; |
c4a69b87 |
8 | use DBIx::Class::Schema::Loader 'make_schema_at'; |
5975bbe6 |
9 | use DBIx::Class::Schema::Loader::Utils 'split_name'; |
10 | use String::ToIdentifier::EN::Unicode 'to_identifier'; |
11 | use namespace::clean; |
c4a69b87 |
12 | |
bc5afe55 |
13 | use lib qw(t/lib); |
c4a69b87 |
14 | |
15 | use dbixcsl_common_tests (); |
16 | use dbixcsl_test_dir '$tdir'; |
17 | |
18 | use constant EXTRA_DUMP_DIR => "$tdir/informix_extra_dump"; |
bc5afe55 |
19 | |
b511f36e |
20 | # to support " quoted identifiers |
21 | BEGIN { $ENV{DELIMIDENT} = 'y' } |
22 | |
bc5afe55 |
23 | # This test doesn't run over a shared memory connection, because of the single connection limit. |
24 | |
25 | my $dsn = $ENV{DBICTEST_INFORMIX_DSN} || ''; |
26 | my $user = $ENV{DBICTEST_INFORMIX_USER} || ''; |
27 | my $password = $ENV{DBICTEST_INFORMIX_PASS} || ''; |
28 | |
c4a69b87 |
29 | my ($schema, $extra_schema); # for cleanup in END for extra tests |
30 | |
bc5afe55 |
31 | my $tester = dbixcsl_common_tests->new( |
32 | vendor => 'Informix', |
c7e6dc1f |
33 | auto_inc_pk => 'serial primary key', |
bc5afe55 |
34 | null => '', |
c7e6dc1f |
35 | default_function => 'current year to fraction(5)', |
36 | default_function_def => 'datetime year to fraction(5) default current year to fraction(5)', |
bc5afe55 |
37 | dsn => $dsn, |
38 | user => $user, |
39 | password => $password, |
b511f36e |
40 | loader_options => { preserve_case => 1 }, |
41 | quote_char => '"', |
c7e6dc1f |
42 | data_types => { |
43 | # http://publib.boulder.ibm.com/infocenter/idshelp/v115/index.jsp?topic=/com.ibm.sqlr.doc/ids_sqr_094.htm |
44 | |
45 | # Numeric Types |
46 | 'int' => { data_type => 'integer' }, |
47 | integer => { data_type => 'integer' }, |
48 | int8 => { data_type => 'bigint' }, |
49 | bigint => { data_type => 'bigint' }, |
50 | serial => { data_type => 'integer', is_auto_increment => 1 }, |
51 | bigserial => { data_type => 'bigint', is_auto_increment => 1 }, |
52 | serial8 => { data_type => 'bigint', is_auto_increment => 1 }, |
53 | smallint => { data_type => 'smallint' }, |
54 | real => { data_type => 'real' }, |
55 | smallfloat => { data_type => 'real' }, |
56 | # just 'double' is a syntax error |
57 | 'double precision' => { data_type => 'double precision' }, |
58 | float => { data_type => 'double precision' }, |
59 | 'float(1)' => { data_type => 'double precision' }, |
60 | 'float(5)' => { data_type => 'double precision' }, |
61 | 'float(10)' => { data_type => 'double precision' }, |
62 | 'float(15)' => { data_type => 'double precision' }, |
63 | 'float(16)' => { data_type => 'double precision' }, |
64 | numeric => { data_type => 'numeric' }, |
65 | decimal => { data_type => 'numeric' }, |
66 | dec => { data_type => 'numeric' }, |
67 | 'numeric(6,3)' => { data_type => 'numeric', size => [6,3] }, |
68 | 'decimal(6,3)' => { data_type => 'numeric', size => [6,3] }, |
69 | 'dec(6,3)' => { data_type => 'numeric', size => [6,3] }, |
70 | |
71 | # Boolean Type |
72 | # XXX this should map to 'boolean' |
73 | boolean => { data_type => 'smallint' }, |
74 | |
75 | # Money Type |
76 | money => { data_type => 'money' }, |
77 | 'money(3,3)' => { data_type => 'numeric', size => [3,3] }, |
78 | |
79 | # Byte Type |
80 | byte => { data_type => 'bytea', original => { data_type => 'byte' } }, |
81 | |
82 | # Character String Types |
83 | char => { data_type => 'char', size => 1 }, |
84 | 'char(3)' => { data_type => 'char', size => 3 }, |
85 | character => { data_type => 'char', size => 1 }, |
86 | 'character(3)' => { data_type => 'char', size => 3 }, |
87 | 'varchar(3)' => { data_type => 'varchar', size => 3 }, |
88 | 'character varying(3)' |
89 | => { data_type => 'varchar', size => 3 }, |
90 | # XXX min size not supported, colmin from syscolumns is NULL |
91 | 'varchar(3,2)' => { data_type => 'varchar', size => 3 }, |
92 | 'character varying(3,2)' |
93 | => { data_type => 'varchar', size => 3 }, |
94 | nchar => { data_type => 'nchar', size => 1 }, |
95 | 'nchar(3)' => { data_type => 'nchar', size => 3 }, |
96 | 'nvarchar(3)' => { data_type => 'nvarchar', size => 3 }, |
97 | 'nvarchar(3,2)' => { data_type => 'nvarchar', size => 3 }, |
98 | 'lvarchar(3)' => { data_type => 'lvarchar', size => 3 }, |
99 | 'lvarchar(33)' => { data_type => 'lvarchar', size => 33 }, |
100 | text => { data_type => 'text' }, |
101 | |
102 | # DateTime Types |
103 | date => { data_type => 'date' }, |
104 | 'date default today' |
105 | => { data_type => 'date', default_value => \'today' }, |
106 | # XXX support all precisions |
107 | 'datetime year to fraction(5)', |
108 | => { data_type => 'datetime year to fraction(5)' }, |
109 | 'datetime year to fraction(5) default current year to fraction(5)', |
110 | => { data_type => 'datetime year to fraction(5)', default_value => \'current year to fraction(5)' }, |
111 | # XXX do interval |
112 | |
113 | # Blob Types |
114 | # XXX no way to distinguish opaque types boolean, blob and clob |
115 | blob => { data_type => 'blob' }, |
116 | clob => { data_type => 'blob' }, |
117 | |
118 | # IDSSECURITYLABEL Type |
119 | # |
120 | # This requires the DBSECADM privilege and a security policy on the |
121 | # table, things I know nothing about. |
122 | # idssecuritylabel => { data_type => 'idssecuritylabel' }, |
123 | |
124 | # List Types |
125 | # XXX need to introspect element type too |
126 | 'list(varchar(20) not null)' |
127 | => { data_type => 'list' }, |
128 | 'multiset(varchar(20) not null)' |
129 | => { data_type => 'multiset' }, |
130 | 'set(varchar(20) not null)' |
131 | => { data_type => 'set' }, |
132 | }, |
c4a69b87 |
133 | extra => { |
5975bbe6 |
134 | count => 26 * 2, |
c4a69b87 |
135 | run => sub { |
136 | ($schema) = @_; |
137 | |
138 | SKIP: { |
5975bbe6 |
139 | skip 'Set the DBICTEST_INFORMIX_EXTRADB_DSN, _USER and _PASS environment variables to run the multi-database tests', 26 * 2 |
c4a69b87 |
140 | unless $ENV{DBICTEST_INFORMIX_EXTRADB_DSN}; |
141 | |
142 | $extra_schema = $schema->clone; |
143 | $extra_schema->connection(@ENV{map "DBICTEST_INFORMIX_EXTRADB_$_", |
144 | qw/DSN USER PASS/ |
145 | }); |
146 | |
147 | my $dbh1 = $schema->storage->dbh; |
c4a69b87 |
148 | |
149 | $dbh1->do(<<'EOF'); |
150 | CREATE TABLE informix_loader_test4 ( |
151 | id SERIAL PRIMARY KEY, |
152 | value VARCHAR(100) |
153 | ) |
154 | EOF |
155 | $dbh1->do(<<'EOF'); |
156 | CREATE TABLE informix_loader_test5 ( |
157 | id SERIAL PRIMARY KEY, |
158 | value VARCHAR(100), |
5975bbe6 |
159 | four_id INTEGER REFERENCES informix_loader_test4 (id) |
c4a69b87 |
160 | ) |
161 | EOF |
5975bbe6 |
162 | $dbh1->do(<<'EOF'); |
163 | ALTER TABLE informix_loader_test5 ADD CONSTRAINT UNIQUE (four_id) CONSTRAINT loader_test5_uniq |
164 | EOF |
e8c7b904 |
165 | |
166 | my $db1 = db_name($schema); |
167 | |
168 | $dbh1->disconnect; |
169 | |
170 | my $dbh2 = $extra_schema->storage->dbh; |
171 | |
5975bbe6 |
172 | $dbh2->do(<<'EOF'); |
173 | CREATE TABLE informix_loader_test5 ( |
174 | pk SERIAL PRIMARY KEY, |
175 | value VARCHAR(100), |
176 | four_id INTEGER |
177 | ) |
178 | EOF |
179 | $dbh2->do(<<'EOF'); |
180 | ALTER TABLE informix_loader_test5 ADD CONSTRAINT UNIQUE (four_id) CONSTRAINT loader_test5_uniq |
181 | EOF |
c4a69b87 |
182 | $dbh2->do(<<"EOF"); |
183 | CREATE TABLE informix_loader_test6 ( |
184 | id SERIAL PRIMARY KEY, |
185 | value VARCHAR(100) |
186 | ) |
187 | EOF |
188 | $dbh2->do(<<"EOF"); |
189 | CREATE TABLE informix_loader_test7 ( |
190 | id SERIAL PRIMARY KEY, |
191 | value VARCHAR(100), |
192 | six_id INTEGER UNIQUE REFERENCES informix_loader_test6 (id) |
193 | ) |
194 | EOF |
c4a69b87 |
195 | |
5975bbe6 |
196 | my $db2 = db_name($extra_schema); |
197 | |
e8c7b904 |
198 | $dbh2->disconnect; |
199 | |
5975bbe6 |
200 | my $db1_moniker = join '', map ucfirst lc, split_name to_identifier $db1; |
201 | my $db2_moniker = join '', map ucfirst lc, split_name to_identifier $db2; |
202 | |
203 | foreach my $db_schema ({ $db1 => '%', $db2 => '%' }, { '%' => '%' }) { |
204 | lives_and { |
205 | my @warns; |
206 | local $SIG{__WARN__} = sub { |
207 | push @warns, $_[0] unless $_[0] =~ /\bcollides\b/ |
208 | || $_[0] =~ /unreferencable/; |
209 | }; |
210 | |
211 | make_schema_at( |
212 | 'InformixMultiDatabase', |
213 | { |
214 | naming => 'current', |
215 | db_schema => $db_schema, |
5975bbe6 |
216 | dump_directory => EXTRA_DUMP_DIR, |
217 | quiet => 1, |
218 | }, |
219 | [ $dsn, $user, $password ], |
220 | ); |
c4a69b87 |
221 | |
e8c7b904 |
222 | InformixMultiDatabase->storage->disconnect; |
223 | |
5975bbe6 |
224 | diag join "\n", @warns if @warns; |
c4a69b87 |
225 | |
5975bbe6 |
226 | is @warns, 0; |
227 | } "dumped schema for databases $db1 and $db2 with no warnings"; |
c4a69b87 |
228 | |
5975bbe6 |
229 | my $test_schema; |
c4a69b87 |
230 | |
5975bbe6 |
231 | lives_and { |
232 | ok $test_schema = InformixMultiDatabase->connect($dsn, $user, $password); |
233 | } 'connected test schema'; |
c4a69b87 |
234 | |
5975bbe6 |
235 | my ($rsrc, $rs, $row, $rel_info, %uniqs); |
c4a69b87 |
236 | |
5975bbe6 |
237 | lives_and { |
4c2e2ce9 |
238 | ok $rsrc = $test_schema->source("InformixLoaderTest4"); |
5975bbe6 |
239 | } 'got source for table in database one'; |
c4a69b87 |
240 | |
5975bbe6 |
241 | is try { $rsrc->column_info('id')->{is_auto_increment} }, 1, |
242 | 'column in database one'; |
c4a69b87 |
243 | |
5975bbe6 |
244 | is try { $rsrc->column_info('value')->{data_type} }, 'varchar', |
245 | 'column in database one'; |
c4a69b87 |
246 | |
5975bbe6 |
247 | is try { $rsrc->column_info('value')->{size} }, 100, |
248 | 'column in database one'; |
c4a69b87 |
249 | |
5975bbe6 |
250 | lives_and { |
4c2e2ce9 |
251 | ok $rs = $test_schema->resultset("InformixLoaderTest4"); |
5975bbe6 |
252 | } 'got resultset for table in database one'; |
c4a69b87 |
253 | |
5975bbe6 |
254 | lives_and { |
255 | ok $row = $rs->create({ value => 'foo' }); |
256 | } 'executed SQL on table in database one'; |
c4a69b87 |
257 | |
5975bbe6 |
258 | $rel_info = try { $rsrc->relationship_info("informix_loader_test5") }; |
c4a69b87 |
259 | |
5975bbe6 |
260 | is_deeply $rel_info->{cond}, { |
261 | 'foreign.four_id' => 'self.id' |
262 | }, 'relationship in database one'; |
c4a69b87 |
263 | |
5975bbe6 |
264 | is $rel_info->{attrs}{accessor}, 'single', |
265 | 'relationship in database one'; |
c4a69b87 |
266 | |
5975bbe6 |
267 | is $rel_info->{attrs}{join_type}, 'LEFT', |
268 | 'relationship in database one'; |
c4a69b87 |
269 | |
5975bbe6 |
270 | lives_and { |
271 | ok $rsrc = $test_schema->source("${db1_moniker}InformixLoaderTest5"); |
272 | } 'got source for table in database one'; |
c4a69b87 |
273 | |
5975bbe6 |
274 | %uniqs = try { $rsrc->unique_constraints }; |
c4a69b87 |
275 | |
5975bbe6 |
276 | is keys %uniqs, 2, |
277 | 'got unique and primary constraint in database one'; |
c4a69b87 |
278 | |
5975bbe6 |
279 | delete $uniqs{primary}; |
c4a69b87 |
280 | |
5975bbe6 |
281 | is_deeply ((values %uniqs)[0], ['four_id'], |
282 | 'correct unique constraint in database one'); |
c4a69b87 |
283 | |
5975bbe6 |
284 | lives_and { |
4c2e2ce9 |
285 | ok $rsrc = $test_schema->source("InformixLoaderTest6"); |
5975bbe6 |
286 | } 'got source for table in database two'; |
c4a69b87 |
287 | |
5975bbe6 |
288 | is try { $rsrc->column_info('id')->{is_auto_increment} }, 1, |
289 | 'column in database two introspected correctly'; |
c4a69b87 |
290 | |
5975bbe6 |
291 | is try { $rsrc->column_info('value')->{data_type} }, 'varchar', |
292 | 'column in database two introspected correctly'; |
c4a69b87 |
293 | |
5975bbe6 |
294 | is try { $rsrc->column_info('value')->{size} }, 100, |
295 | 'column in database two introspected correctly'; |
c4a69b87 |
296 | |
5975bbe6 |
297 | lives_and { |
4c2e2ce9 |
298 | ok $rs = $test_schema->resultset("InformixLoaderTest6"); |
5975bbe6 |
299 | } 'got resultset for table in database two'; |
c4a69b87 |
300 | |
5975bbe6 |
301 | lives_and { |
302 | ok $row = $rs->create({ value => 'foo' }); |
303 | } 'executed SQL on table in database two'; |
c4a69b87 |
304 | |
5975bbe6 |
305 | $rel_info = try { $rsrc->relationship_info('informix_loader_test7') }; |
c4a69b87 |
306 | |
5975bbe6 |
307 | is_deeply $rel_info->{cond}, { |
308 | 'foreign.six_id' => 'self.id' |
309 | }, 'relationship in database two'; |
c4a69b87 |
310 | |
5975bbe6 |
311 | is $rel_info->{attrs}{accessor}, 'single', |
312 | 'relationship in database two'; |
c4a69b87 |
313 | |
5975bbe6 |
314 | is $rel_info->{attrs}{join_type}, 'LEFT', |
315 | 'relationship in database two'; |
316 | |
317 | lives_and { |
4c2e2ce9 |
318 | ok $rsrc = $test_schema->source("InformixLoaderTest7"); |
5975bbe6 |
319 | } 'got source for table in database two'; |
320 | |
321 | %uniqs = try { $rsrc->unique_constraints }; |
322 | |
323 | is keys %uniqs, 2, |
324 | 'got unique and primary constraint in database two'; |
325 | |
326 | delete $uniqs{primary}; |
327 | |
328 | is_deeply ((values %uniqs)[0], ['six_id'], |
329 | 'correct unique constraint in database two'); |
330 | } |
c4a69b87 |
331 | } |
332 | }, |
333 | }, |
bc5afe55 |
334 | ); |
335 | |
336 | if( !$dsn ) { |
337 | $tester->skip_tests('You need to set the DBICTEST_INFORMIX_DSN, _USER, and _PASS environment variables'); |
338 | } |
4fb2971c |
339 | elsif (!DBIx::Class::Optional::Dependencies->req_ok_for ('rdbms_informix')) { |
340 | $tester->skip_tests('You need to install ' . DBIx::Class::Optional::Dependencies->req_missing_for ('rdbms_informix')); |
341 | } |
bc5afe55 |
342 | else { |
343 | $tester->run_tests(); |
344 | } |
c4a69b87 |
345 | |
5975bbe6 |
346 | sub db_name { |
347 | my $schema = shift; |
348 | |
349 | # When we clone the schema, it still references the original loader, which |
350 | # references the original schema. |
351 | local $schema->loader->{schema} = $schema; |
352 | |
353 | return $schema->loader->_current_db; |
e8c7b904 |
354 | |
355 | $schema->storage->disconnect; |
5975bbe6 |
356 | } |
357 | |
c4a69b87 |
358 | END { |
359 | if (not $ENV{SCHEMA_LOADER_TESTS_NOCLEANUP}) { |
360 | if (my $dbh2 = try { $extra_schema->storage->dbh }) { |
c4a69b87 |
361 | |
362 | try { |
363 | $dbh2->do('DROP TABLE informix_loader_test7'); |
364 | $dbh2->do('DROP TABLE informix_loader_test6'); |
5975bbe6 |
365 | $dbh2->do('DROP TABLE informix_loader_test5'); |
e8c7b904 |
366 | } |
367 | catch { |
368 | die "Error dropping test tables: $_"; |
369 | }; |
370 | |
371 | $dbh2->disconnect; |
372 | } |
373 | |
374 | if (my $dbh1 = try { $schema->storage->dbh }) { |
375 | |
376 | try { |
c4a69b87 |
377 | $dbh1->do('DROP TABLE informix_loader_test5'); |
378 | $dbh1->do('DROP TABLE informix_loader_test4'); |
379 | } |
380 | catch { |
381 | die "Error dropping test tables: $_"; |
382 | }; |
e8c7b904 |
383 | |
384 | $dbh1->disconnect; |
c4a69b87 |
385 | } |
386 | |
387 | rmtree EXTRA_DUMP_DIR; |
388 | } |
389 | } |
bc5afe55 |
390 | # vim:et sts=4 sw=4 tw=0: |