Merge 'trunk' into 'sybase'
[dbsrgits/DBIx-Class.git] / t / 746mssql.t
CommitLineData
c1cac633 1use strict;
b9a2c3a5 2use warnings;
c1cac633 3
4use Test::More;
893403c8 5use Test::Exception;
c1cac633 6use lib qw(t/lib);
7use DBICTest;
b2d16f1f 8use DBIC::SqlMakerTest;
c1cac633 9
10my ($dsn, $user, $pass) = @ENV{map { "DBICTEST_MSSQL_ODBC_${_}" } qw/DSN USER PASS/};
11
12plan skip_all => 'Set $ENV{DBICTEST_MSSQL_ODBC_DSN}, _USER and _PASS to run this test'
13 unless ($dsn && $user);
14
ca791b95 15plan tests => 39;
c1cac633 16
ca791b95 17DBICTest::Schema->load_classes('ArtistGUID');
42e5b103 18my $schema = DBICTest::Schema->connect($dsn, $user, $pass);
c1cac633 19
8c0104fe 20{
21 no warnings 'redefine';
22 my $connect_count = 0;
23 my $orig_connect = \&DBI::connect;
24 local *DBI::connect = sub { $connect_count++; goto &$orig_connect };
25
26 $schema->storage->ensure_connected;
27
28 is( $connect_count, 1, 'only one connection made');
29}
9b3e916d 30
c1cac633 31isa_ok( $schema->storage, 'DBIx::Class::Storage::DBI::ODBC::Microsoft_SQL_Server' );
32
c5f77f6c 33$schema->storage->dbh_do (sub {
34 my ($storage, $dbh) = @_;
35 eval { $dbh->do("DROP TABLE artist") };
36 $dbh->do(<<'SQL');
c1cac633 37CREATE TABLE artist (
38 artistid INT IDENTITY NOT NULL,
a0dd8679 39 name VARCHAR(100),
39da2a2b 40 rank INT NOT NULL DEFAULT '13',
2eebd801 41 charfield CHAR(10) NULL,
c1cac633 42 primary key(artistid)
43)
c5f77f6c 44SQL
c5f77f6c 45});
46
c1cac633 47my %seen_id;
48
7b1b2582 49my @opts = (
50 { on_connect_call => 'use_dynamic_cursors' },
51 {},
52);
53my $new;
2eebd801 54
7b1b2582 55# test Auto-PK with different options
56for my $opts (@opts) {
41dd5d30 57 SKIP: {
58 $schema = DBICTest::Schema->connect($dsn, $user, $pass, $opts);
7b1b2582 59
41dd5d30 60 eval {
61 $schema->storage->ensure_connected
62 };
63 if ($@ =~ /dynamic cursors/) {
64 skip
65'Dynamic Cursors not functional, tds_version 8.0 or greater required if using'.
66' FreeTDS', 1;
67 }
2eebd801 68
41dd5d30 69 $schema->resultset('Artist')->search({ name => 'foo' })->delete;
70
71 $new = $schema->resultset('Artist')->create({ name => 'foo' });
72
73 ok($new->artistid > 0, "Auto-PK worked");
74 }
7b1b2582 75}
c1cac633 76
77$seen_id{$new->artistid}++;
78
79# test LIMIT support
80for (1..6) {
81 $new = $schema->resultset('Artist')->create({ name => 'Artist ' . $_ });
82 is ( $seen_id{$new->artistid}, undef, "id for Artist $_ is unique" );
83 $seen_id{$new->artistid}++;
84}
85
86my $it = $schema->resultset('Artist')->search( {}, {
87 rows => 3,
88 order_by => 'artistid',
89});
90
91is( $it->count, 3, "LIMIT count ok" );
92is( $it->next->name, "foo", "iterator->next ok" );
93$it->next;
94is( $it->next->name, "Artist 2", "iterator->next ok" );
95is( $it->next, undef, "next past end of resultset ok" );
96
ca791b95 97# test GUID columns
98
99$schema->storage->dbh_do (sub {
100 my ($storage, $dbh) = @_;
101 eval { $dbh->do("DROP TABLE artist") };
102 $dbh->do(<<'SQL');
103CREATE TABLE artist (
104 artistid UNIQUEIDENTIFIER NOT NULL,
105 name VARCHAR(100),
106 rank INT NOT NULL DEFAULT '13',
107 charfield CHAR(10) NULL,
108 a_guid UNIQUEIDENTIFIER,
109 primary key(artistid)
110)
111SQL
112});
113
e34bae3a 114# start disconnected to make sure insert works on an un-reblessed storage
115$schema = DBICTest::Schema->connect($dsn, $user, $pass);
116
ca791b95 117my $row;
118lives_ok {
119 $row = $schema->resultset('ArtistGUID')->create({ name => 'mtfnpy' })
120} 'created a row with a GUID';
121
122ok(
123 eval { $row->artistid },
124 'row has GUID PK col populated',
125);
126diag $@ if $@;
127
128ok(
129 eval { $row->a_guid },
130 'row has a GUID col with auto_nextval populated',
131);
132diag $@ if $@;
133
134my $row_from_db = $schema->resultset('ArtistGUID')
135 ->search({ name => 'mtfnpy' })->first;
136
137is $row_from_db->artistid, $row->artistid,
138 'PK GUID round trip';
139
140is $row_from_db->a_guid, $row->a_guid,
141 'NON-PK GUID round trip';
142
818ec409 143# test MONEY type
144$schema->storage->dbh_do (sub {
145 my ($storage, $dbh) = @_;
146 eval { $dbh->do("DROP TABLE money_test") };
147 $dbh->do(<<'SQL');
818ec409 148CREATE TABLE money_test (
149 id INT IDENTITY PRIMARY KEY,
5064f5c3 150 amount MONEY NULL
818ec409 151)
818ec409 152SQL
818ec409 153});
154
155my $rs = $schema->resultset('Money');
156
818ec409 157lives_ok {
d68f21ee 158 $row = $rs->create({ amount => 100 });
818ec409 159} 'inserted a money value';
160
161is $rs->find($row->id)->amount, '100.00', 'money value round-trip';
162
d68f21ee 163lives_ok {
164 $row->update({ amount => 200 });
165} 'updated a money value';
166
167is $rs->find($row->id)->amount, '200.00', 'updated money value round-trip';
168
f6b185e1 169lives_ok {
170 $row->update({ amount => undef });
171} 'updated a money value to NULL';
172
173is $rs->find($row->id)->amount, undef,'updated money value to NULL round-trip';
174
b9a2c3a5 175$schema->storage->dbh_do (sub {
176 my ($storage, $dbh) = @_;
177 eval { $dbh->do("DROP TABLE Owners") };
178 eval { $dbh->do("DROP TABLE Books") };
179 $dbh->do(<<'SQL');
b9a2c3a5 180CREATE TABLE Books (
181 id INT IDENTITY (1, 1) NOT NULL,
182 source VARCHAR(100),
183 owner INT,
184 title VARCHAR(10),
185 price INT NULL
186)
187
188CREATE TABLE Owners (
189 id INT IDENTITY (1, 1) NOT NULL,
42e5b103 190 name VARCHAR(100),
b9a2c3a5 191)
b9a2c3a5 192SQL
193
194});
893403c8 195
196lives_ok ( sub {
197 $schema->populate ('Owners', [
198 [qw/id name /],
199 [qw/1 wiggle/],
200 [qw/2 woggle/],
201 [qw/3 boggle/],
202 [qw/4 fREW/],
203 [qw/5 fRIOUX/],
204 [qw/6 fROOH/],
205 [qw/7 fRUE/],
206 [qw/8 fISMBoC/],
207 [qw/9 station/],
208 [qw/10 mirror/],
209 [qw/11 dimly/],
210 [qw/12 face_to_face/],
211 [qw/13 icarus/],
212 [qw/14 dream/],
213 [qw/15 dyrstyggyr/],
214 ]);
215}, 'populate with PKs supplied ok' );
216
217lives_ok ( sub {
218 $schema->populate ('BooksInLibrary', [
219 [qw/source owner title /],
220 [qw/Library 1 secrets0/],
221 [qw/Library 1 secrets1/],
222 [qw/Eatery 1 secrets2/],
223 [qw/Library 2 secrets3/],
224 [qw/Library 3 secrets4/],
225 [qw/Eatery 3 secrets5/],
226 [qw/Library 4 secrets6/],
227 [qw/Library 5 secrets7/],
228 [qw/Eatery 5 secrets8/],
229 [qw/Library 6 secrets9/],
230 [qw/Library 7 secrets10/],
231 [qw/Eatery 7 secrets11/],
232 [qw/Library 8 secrets12/],
233 ]);
234}, 'populate without PKs supplied ok' );
b9a2c3a5 235
236#
02d133f0 237# try a prefetch on tables with identically named columns
b9a2c3a5 238#
239
02d133f0 240# set quote char - make sure things work while quoted
241$schema->storage->_sql_maker->{quote_char} = [qw/[ ]/];
242$schema->storage->_sql_maker->{name_sep} = '.';
243
b9a2c3a5 244{
893403c8 245 # try a ->has_many direction
fc85215b 246 my $owners = $schema->resultset ('Owners')->search ({
247 'books.id' => { '!=', undef }
248 }, {
249 prefetch => 'books',
ff1ef65b 250 order_by => 'name',
56d2561e 251 rows => 3, # 8 results total
fc85215b 252 });
253
56d2561e 254 is ($owners->page(1)->all, 3, 'has_many prefetch returns correct number of rows');
255 is ($owners->page(1)->count, 3, 'has-many prefetch returns correct count');
256
618a0fe3 257 TODO: {
258 local $TODO = 'limit past end of resultset problem';
56d2561e 259 is ($owners->page(3)->all, 2, 'has_many prefetch returns correct number of rows');
260 is ($owners->page(3)->count, 2, 'has-many prefetch returns correct count');
64c7c000 261 is ($owners->page(3)->count_rs->next, 2, 'has-many prefetch returns correct count_rs');
262
263 # make sure count does not become overly complex FIXME
264 is_same_sql_bind (
265 $owners->page(3)->count_rs->as_query,
266 '(
267 SELECT COUNT( * )
268 FROM (
02d133f0 269 SELECT TOP 3 [me].[id]
270 FROM [owners] [me]
271 LEFT JOIN [books] [books] ON [books].[owner] = [me].[id]
272 WHERE ( [books].[id] IS NOT NULL )
273 GROUP BY [me].[id]
274 ORDER BY [me].[id] DESC
275 ) [count_subq]
64c7c000 276 )',
277 [],
278 );
618a0fe3 279 }
b9a2c3a5 280
42e5b103 281 # try a ->belongs_to direction (no select collapse, group_by should work)
fc85215b 282 my $books = $schema->resultset ('BooksInLibrary')->search ({
56d2561e 283 'owner.name' => [qw/wiggle woggle/],
fc85215b 284 }, {
fc85215b 285 distinct => 1,
42e5b103 286 prefetch => 'owner',
56d2561e 287 rows => 2, # 3 results total
ac93965c 288 order_by => { -desc => 'owner' },
289 # there is no sane way to order by the right side of a grouped prefetch currently :(
290 #order_by => { -desc => 'owner.name' },
fc85215b 291 });
292
b1e1d073 293
56d2561e 294 is ($books->page(1)->all, 2, 'Prefetched grouped search returns correct number of rows');
295 is ($books->page(1)->count, 2, 'Prefetched grouped search returns correct count');
b1e1d073 296
618a0fe3 297 TODO: {
298 local $TODO = 'limit past end of resultset problem';
56d2561e 299 is ($books->page(2)->all, 1, 'Prefetched grouped search returns correct number of rows');
300 is ($books->page(2)->count, 1, 'Prefetched grouped search returns correct count');
64c7c000 301 is ($books->page(2)->count_rs->next, 1, 'Prefetched grouped search returns correct count_rs');
302
303 # make sure count does not become overly complex FIXME
304 is_same_sql_bind (
305 $books->page(2)->count_rs->as_query,
306 '(
307 SELECT COUNT( * )
308 FROM (
02d133f0 309 SELECT TOP 2 [me].[id]
310 FROM [books] [me]
311 JOIN [owners] [owner] ON [owner].[id] = [me].[owner]
312 WHERE ( ( ( [owner].[name] = ? OR [owner].[name] = ? ) AND [source] = ? ) )
313 GROUP BY [me].[id], [me].[source], [me].[owner], [me].[title], [me].[price], [owner].[id], [owner].[name]
314 ORDER BY [me].[id] DESC
315 ) [count_subq]
64c7c000 316 )',
317 [
318 [ 'owner.name' => 'wiggle' ],
319 [ 'owner.name' => 'woggle' ],
320 [ 'source' => 'Library' ],
321 ],
322 );
618a0fe3 323 }
b2d16f1f 324
b9a2c3a5 325}
c1cac633 326
327# clean up our mess
328END {
e06ad5d5 329 if (my $dbh = eval { $schema->storage->_dbh }) {
330 eval { $dbh->do("DROP TABLE $_") }
331 for qw/artist money_test Books Owners/;
332 }
c1cac633 333}
fc85215b 334# vim:sw=2 sts=2