Extra tests for all the improvements
[dbsrgits/DBIx-Class.git] / t / sqlmaker / limit_dialects / torture.t
CommitLineData
27a7c422 1use strict;
2use warnings;
3
4use Test::More;
5use lib qw(t/lib);
6use DBICTest;
7use DBIC::SqlMakerTest;
8
9my $schema = DBICTest->init_schema;
10
11my $attr = {};
12my @where_bind = (
13 [ { sqlt_datatype => 'varchar', sqlt_size => 100, dbic_colname => 'source' } => 'Study' ],
14 [ { sqlt_datatype => 'varchar', sqlt_size => 100, dbic_colname => 'me.title' } => 'kama sutra' ],
15 [ { sqlt_datatype => 'varchar', sqlt_size => 100, dbic_colname => 'source' } => 'Library' ],
16);
17my @select_bind = (
18 [ $attr => 11 ], [ $attr => 12 ], [ $attr => 13 ],
19);
20my @group_bind = (
21 [ $attr => 21 ],
22);
23my @having_bind = (
24 [ $attr => 31 ],
25);
26my @order_bind = (
27 [ $attr => 1 ], [ $attr => 2 ], [ $attr => 3 ],
28);
29
30my $tests = {
31 LimitOffset => {
32 ordered_limit_offset => [
33 '(
34 SELECT me.id, ? * ?, ?
35 FROM books me
36 WHERE source != ? AND me.title = ? AND source = ?
37 GROUP BY avg(me.id / ?)
38 HAVING ?
39 ORDER BY ? / ?, ?
40 LIMIT ?
41 OFFSET ?
42 )',
43 [
44 @select_bind,
45 @where_bind,
46 @group_bind,
47 @having_bind,
48 @order_bind,
49 [ { sqlt_datatype => 'integer' } => 4 ],
50 [ { sqlt_datatype => 'integer' } => 3 ],
51 ],
52 ],
53 },
54
55 LimitXY => {
56 ordered_limit_offset => [
57 '(
58 SELECT me.id, ? * ?, ?
59 FROM books me
60 WHERE source != ? AND me.title = ? AND source = ?
61 GROUP BY avg(me.id / ?)
62 HAVING ?
63 ORDER BY ? / ?, ?
64 LIMIT ?, ?
65 )',
66 [
67 @select_bind,
68 @where_bind,
69 @group_bind,
70 @having_bind,
71 @order_bind,
72 [ { sqlt_datatype => 'integer' } => 3 ],
73 [ { sqlt_datatype => 'integer' } => 4 ],
74 ],
75 ],
76 },
77
78 SkipFirst => {
79 ordered_limit_offset => [
80 '(
81 SELECT SKIP ? FIRST ? me.id, ? * ?, ?
82 FROM books me
83 WHERE source != ? AND me.title = ? AND source = ?
84 GROUP BY avg(me.id / ?)
85 HAVING ?
86 ORDER BY ? / ?, ?
87 )',
88 [
89 [ { sqlt_datatype => 'integer' } => 3 ],
90 [ { sqlt_datatype => 'integer' } => 4 ],
91 @select_bind,
92 @where_bind,
93 @group_bind,
94 @having_bind,
95 @order_bind,
96 ],
97 ],
98 },
99
100 FirstSkip => {
101 ordered_limit_offset => [
102 '(
103 SELECT FIRST ? SKIP ? me.id, ? * ?, ?
104 FROM books me
105 WHERE source != ? AND me.title = ? AND source = ?
106 GROUP BY avg(me.id / ?)
107 HAVING ?
108 ORDER BY ? / ?, ?
109 )',
110 [
111 [ { sqlt_datatype => 'integer' } => 4 ],
112 [ { sqlt_datatype => 'integer' } => 3 ],
113 @select_bind,
114 @where_bind,
115 @group_bind,
116 @having_bind,
117 @order_bind,
118 ],
119 ],
120 },
121
122 RowNumberOver => do {
123 my $unordered_sql = '(
124 SELECT me.id, bar, baz
125 FROM (
126 SELECT me.id, bar, baz, ROW_NUMBER() OVER() AS rno__row__index
127 FROM (
128 SELECT me.id, ? * ? AS bar, ? AS baz
129 FROM books me
130 WHERE source != ? AND me.title = ? AND source = ?
131 GROUP BY avg(me.id / ?)
132 HAVING ?
133 ) me
134 ) me
135 WHERE rno__row__index >= ? AND rno__row__index <= ?
136 )';
137
138 my $ordered_sql = '(
139 SELECT me.id, bar, baz
140 FROM (
141 SELECT me.id, bar, baz, ROW_NUMBER() OVER( ORDER BY ORDER__BY__1, ORDER__BY__2 ) AS rno__row__index
142 FROM (
143 SELECT me.id, ? * ? AS bar, ? AS baz,
144 ? / ? AS ORDER__BY__1, ? AS ORDER__BY__2
145 FROM books me
146 WHERE source != ? AND me.title = ? AND source = ?
147 GROUP BY avg(me.id / ?)
148 HAVING ?
149 ) me
150 ) me
151 WHERE rno__row__index >= ? AND rno__row__index <= ?
152 )';
153
154 {
155 limit => [$unordered_sql,
156 [
157 @select_bind,
158 @where_bind,
159 @group_bind,
160 @having_bind,
161 [ { sqlt_datatype => 'integer' } => 1 ],
162 [ { sqlt_datatype => 'integer' } => 4 ],
163 ],
164 ],
165 limit_offset => [$unordered_sql,
166 [
167 @select_bind,
168 @where_bind,
169 @group_bind,
170 @having_bind,
171 [ { sqlt_datatype => 'integer' } => 4 ],
172 [ { sqlt_datatype => 'integer' } => 7 ],
173 ],
174 ],
175 ordered_limit => [$ordered_sql,
176 [
177 @select_bind,
178 @order_bind,
179 @where_bind,
180 @group_bind,
181 @having_bind,
182 [ { sqlt_datatype => 'integer' } => 1 ],
183 [ { sqlt_datatype => 'integer' } => 4 ],
184 ],
185 ],
186 ordered_limit_offset => [$ordered_sql,
187 [
188 @select_bind,
189 @order_bind,
190 @where_bind,
191 @group_bind,
192 @having_bind,
193 [ { sqlt_datatype => 'integer' } => 4 ],
194 [ { sqlt_datatype => 'integer' } => 7 ],
195 ],
196 ],
197 };
198 },
199
200 RowNum => do {
201 my $limit_sql = sub {
202 sprintf '(
203 SELECT me.id, bar, baz
204 FROM (
205 SELECT me.id, ? * ? AS bar, ? AS baz
206 FROM books me
207 WHERE source != ? AND me.title = ? AND source = ?
208 GROUP BY avg(me.id / ?)
209 HAVING ?
210 %s
211 ) me
212 WHERE ROWNUM <= ?
213 )', $_[0] || '';
214 };
215
216 {
217 limit => [ $limit_sql->(),
218 [
219 @select_bind,
220 @where_bind,
221 @group_bind,
222 @having_bind,
223 [ { sqlt_datatype => 'integer' } => 4 ],
224 ],
225 ],
226 limit_offset => [
227 '(
228 SELECT me.id, bar, baz
229 FROM (
230 SELECT me.id, bar, baz, ROWNUM rownum__index
231 FROM (
232 SELECT me.id, ? * ? AS bar, ? AS baz
233 FROM books me
234 WHERE source != ? AND me.title = ? AND source = ?
235 GROUP BY avg(me.id / ?)
236 HAVING ?
237 ) me
238 ) me
239 WHERE rownum__index BETWEEN ? AND ?
240 )',
241 [
242 @select_bind,
243 @where_bind,
244 @group_bind,
245 @having_bind,
246 [ { sqlt_datatype => 'integer' } => 4 ],
247 [ { sqlt_datatype => 'integer' } => 7 ],
248 ],
249 ],
250 ordered_limit => [ $limit_sql->('ORDER BY ? / ?, ?'),
251 [
252 @select_bind,
253 @where_bind,
254 @group_bind,
255 @having_bind,
256 @order_bind,
257 [ { sqlt_datatype => 'integer' } => 4 ],
258 ],
259 ],
260 ordered_limit_offset => [
261 '(
262 SELECT me.id, bar, baz
263 FROM (
264 SELECT me.id, bar, baz, ROWNUM rownum__index
265 FROM (
266 SELECT me.id, ? * ? AS bar, ? AS baz
267 FROM books me
268 WHERE source != ? AND me.title = ? AND source = ?
269 GROUP BY avg(me.id / ?)
270 HAVING ?
271 ORDER BY ? / ?, ?
272 ) me
273 WHERE ROWNUM <= ?
274 ) me
275 WHERE rownum__index >= ?
276 )',
277 [
278 @select_bind,
279 @where_bind,
280 @group_bind,
281 @having_bind,
282 @order_bind,
283 [ { sqlt_datatype => 'integer' } => 7 ],
284 [ { sqlt_datatype => 'integer' } => 4 ],
285 ],
286 ],
287 };
288 },
289
290
291 FetchFirst => {
292 limit => [
293 '(
294 SELECT me.id, ? * ?, ?
295 FROM books me
296 WHERE source != ? AND me.title = ? AND source = ?
297 GROUP BY avg(me.id / ?)
298 HAVING ?
299 FETCH FIRST 4 ROWS ONLY
300 )',
301 [
302 @select_bind,
303 @where_bind,
304 @group_bind,
305 @having_bind,
306 ],
307 ],
308 limit_offset => [
309 '(
310 SELECT me.id, bar, baz
311 FROM (
312 SELECT me.id, ? * ? AS bar, ? AS baz
313 FROM books me
314 WHERE source != ? AND me.title = ? AND source = ?
315 GROUP BY avg(me.id / ?)
316 HAVING ?
317 ORDER BY me.id
318 FETCH FIRST 7 ROWS ONLY
319 ) me
320 ORDER BY me.id DESC
321 FETCH FIRST 4 ROWS ONLY
322 )',
323 [
324 @select_bind,
325 @where_bind,
326 @group_bind,
327 @having_bind,
328 ],
329 ],
330 ordered_limit => [
331 '(
332 SELECT me.id, ? * ?, ?
333 FROM books me
334 WHERE source != ? AND me.title = ? AND source = ?
335 GROUP BY avg(me.id / ?)
336 HAVING ?
337 ORDER BY ? / ?, ?
338 FETCH FIRST 4 ROWS ONLY
339 )',
340 [
341 @select_bind,
342 @where_bind,
343 @group_bind,
344 @having_bind,
345 @order_bind,
346 ],
347 ],
348 ordered_limit_offset => [
349 '(
350 SELECT me.id, bar, baz
351 FROM (
352 SELECT me.id, bar, baz, ORDER__BY__1, ORDER__BY__2
353 FROM (
354 SELECT me.id, ? * ? AS bar, ? AS baz, ? / ? AS ORDER__BY__1, ? AS ORDER__BY__2
355 FROM books me
356 WHERE source != ? AND me.title = ? AND source = ?
357 GROUP BY avg(me.id / ?)
358 HAVING ?
359 ORDER BY ? / ?, ?
360 FETCH FIRST 7 ROWS ONLY
361 ) me
362 ORDER BY ORDER__BY__1 DESC, ORDER__BY__2 DESC
363 FETCH FIRST 4 ROWS ONLY
364 ) me
365 ORDER BY ORDER__BY__1, ORDER__BY__2
366 )',
367 [
368 @select_bind,
369 @order_bind,
370 @where_bind,
371 @group_bind,
372 @having_bind,
373 (map { [ @$_ ] } @order_bind), # without this is_deeply throws a fit
374 ],
375 ],
376 },
377
378 Top => {
379 limit => [
380 '(
381 SELECT TOP 4 me.id, ? * ?, ?
382 FROM books me
383 WHERE source != ? AND me.title = ? AND source = ?
384 GROUP BY avg(me.id / ?)
385 HAVING ?
386 )',
387 [
388 @select_bind,
389 @where_bind,
390 @group_bind,
391 @having_bind,
392 ],
393 ],
394 limit_offset => [
395 '(
396 SELECT TOP 4 me.id, bar, baz
397 FROM (
398 SELECT TOP 7 me.id, ? * ? AS bar, ? AS baz
399 FROM books me
400 WHERE source != ? AND me.title = ? AND source = ?
401 GROUP BY avg(me.id / ?)
402 HAVING ?
403 ORDER BY me.id
404 ) me
405 ORDER BY me.id DESC
406 )',
407 [
408 @select_bind,
409 @where_bind,
410 @group_bind,
411 @having_bind,
412 ],
413 ],
414 ordered_limit => [
415 '(
416 SELECT TOP 4 me.id, ? * ?, ?
417 FROM books me
418 WHERE source != ? AND me.title = ? AND source = ?
419 GROUP BY avg(me.id / ?)
420 HAVING ?
421 ORDER BY ? / ?, ?
422 )',
423 [
424 @select_bind,
425 @where_bind,
426 @group_bind,
427 @having_bind,
428 @order_bind,
429 ],
430 ],
431 ordered_limit_offset => [
432 '(
433 SELECT me.id, bar, baz
434 FROM (
435 SELECT TOP 4 me.id, bar, baz, ORDER__BY__1, ORDER__BY__2
436 FROM (
437 SELECT TOP 7 me.id, ? * ? AS bar, ? AS baz, ? / ? AS ORDER__BY__1, ? AS ORDER__BY__2
438 FROM books me
439 WHERE source != ? AND me.title = ? AND source = ?
440 GROUP BY avg(me.id / ?)
441 HAVING ?
442 ORDER BY ? / ?, ?
443 ) me
444 ORDER BY ORDER__BY__1 DESC, ORDER__BY__2 DESC
445 ) me
446 ORDER BY ORDER__BY__1, ORDER__BY__2
447 )',
448 [
449 @select_bind,
450 @order_bind,
451 @where_bind,
452 @group_bind,
453 @having_bind,
454 (map { [ @$_ ] } @order_bind), # without this is_deeply throws a fit
455 ],
456 ],
457 },
458
459 RowCountOrGenericSubQ => {
460 limit => [
461 '(
462 SET ROWCOUNT 4
463 SELECT me.id, ? * ?, ?
464 FROM books me
465 WHERE source != ? AND me.title = ? AND source = ?
466 GROUP BY avg(me.id / ?)
467 HAVING ?
468 ORDER BY me.id
469 SET ROWCOUNT 0
470 )',
471 [
472 @select_bind,
473 @where_bind,
474 @group_bind,
475 @having_bind,
476 ],
477 ],
478 limit_offset => [
479 '(
480 SELECT me.id, bar, baz
481 FROM (
482 SELECT me.id, ? * ? AS bar, ? AS baz
483 FROM books me
484 WHERE source != ? AND me.title = ? AND source = ?
485 GROUP BY avg( me.id / ? )
486 HAVING ?
487 ) me
488 WHERE (
489 SELECT COUNT( * )
490 FROM books rownum__emulation
491 WHERE rownum__emulation.id < me.id
492 ) BETWEEN ? AND ?
493 ORDER BY me.id
494 )',
495 [
496 @select_bind,
497 @where_bind,
498 @group_bind,
499 @having_bind,
500 [ { sqlt_datatype => 'integer' } => 3 ],
501 [ { sqlt_datatype => 'integer' } => 6 ],
502 ],
503 ],
504 },
505
506 GenericSubQ => {
507 limit => [
508 '(
509 SELECT me.id, bar, baz
510 FROM (
511 SELECT me.id, ? * ? AS bar, ? AS baz
512 FROM books me
513 WHERE source != ? AND me.title = ? AND source = ?
514 GROUP BY avg( me.id / ? )
515 HAVING ?
516 ) me
517 WHERE (
518 SELECT COUNT( * )
519 FROM books rownum__emulation
520 WHERE rownum__emulation.id < me.id
521 ) < ?
522 ORDER BY me.id
523 )',
524 [
525 @select_bind,
526 @where_bind,
527 @group_bind,
528 @having_bind,
529 [ { sqlt_datatype => 'integer' } => 4 ],
530 ],
531 ],
532 limit_offset => [
533 '(
534 SELECT me.id, bar, baz
535 FROM (
536 SELECT me.id, ? * ? AS bar, ? AS baz
537 FROM books me
538 WHERE source != ? AND me.title = ? AND source = ?
539 GROUP BY avg( me.id / ? )
540 HAVING ?
541 ) me
542 WHERE (
543 SELECT COUNT( * )
544 FROM books rownum__emulation
545 WHERE rownum__emulation.id < me.id
546 ) BETWEEN ? AND ?
547 ORDER BY me.id
548 )',
549 [
550 @select_bind,
551 @where_bind,
552 @group_bind,
553 @having_bind,
554 [ { sqlt_datatype => 'integer' } => 3 ],
555 [ { sqlt_datatype => 'integer' } => 6 ],
556 ],
557 ],
558 }
559};
560
561for my $limtype (sort keys %$tests) {
562
563 delete $schema->storage->_sql_maker->{_cached_syntax};
564 $schema->storage->_sql_maker->limit_dialect ($limtype);
565
566 # chained search is necessary to exercise the recursive {where} parser
567 my $rs = $schema->resultset('BooksInLibrary')->search({ 'me.title' => { '=' => 'kama sutra' } })->search({ source => { '!=', 'Study' } }, {
568 columns => { identifier => 'me.id' }, # people actually do that. BLEH!!! :)
569 rows => 4,
570 '+columns' => { bar => \['? * ?', [ $attr => 11 ], [ $attr => 12 ]], baz => \[ '?', [ $attr => 13 ]] },
571 group_by => \[ 'avg(me.id / ?)', [ $attr => 21 ] ],
572 having => \[ '?', [ $attr => 31 ] ],
573 ($limtype =~ /GenericSubQ/ ? ( order_by => 'me.id' ) : () ), # needs a simple-column stable order to be happy
574 });
575
576 #
577 # not all tests run on all dialects (somewhere impossible, somewhere makes no sense)
578 #
579
580 # only limit, no offset, no order
581 is_same_sql_bind(
582 $rs->as_query,
583 @{$tests->{$limtype}{limit}},
584 "$limtype: Unordered limit with select/group/having",
585 ) if $tests->{$limtype}{limit};
586
587 # limit + offset, no order
588 is_same_sql_bind(
589 $rs->search({}, { offset => 3 })->as_query,
590 @{$tests->{$limtype}{limit_offset}},
591 "$limtype: Unordered limit+offset with select/group/having",
592 ) if $tests->{$limtype}{limit_offset};
593
594 # order + limit, no offset
595 $rs = $rs->search(undef, {
596 order_by => [ \['? / ?', [ $attr => 1 ], [ $attr => 2 ]], \[ '?', [ $attr => 3 ]] ],
597 });
598
599 is_same_sql_bind(
600 $rs->as_query,
601 @{$tests->{$limtype}{ordered_limit}},
602 "$limtype: Ordered limit with select/group/having",
603 ) if $tests->{$limtype}{ordered_limit};
604
605 # order + limit + offset
606 is_same_sql_bind(
607 $rs->search({}, { offset => 3 })->as_query,
608 @{$tests->{$limtype}{ordered_limit_offset}},
609 "$limtype: Ordered limit+offset with select/group/having",
610 ) if $tests->{$limtype}{ordered_limit_offset};
611}
612
613done_testing;