Remove idiotic RowCountOrGenericSubQ - it will never work as part of as_query
[dbsrgits/DBIx-Class.git] / t / sqlmaker / limit_dialects / torture.t
1 use strict;
2 use warnings;
3
4 use Test::More;
5 use Test::Exception;
6 use lib qw(t/lib);
7 use DBICTest;
8 use DBIC::SqlMakerTest;
9
10 my $schema = DBICTest->init_schema;
11 my $native_limit_dialect = $schema->storage->sql_maker->{limit_dialect};
12
13 my $attr = {};
14 my @where_bind = (
15   [ { sqlt_datatype => 'varchar', sqlt_size => 100, dbic_colname => 'source' } => 'Study' ],
16   [ { sqlt_datatype => 'varchar', sqlt_size => 100, dbic_colname => 'me.title' } => 'kama sutra' ],
17   [ { sqlt_datatype => 'varchar', sqlt_size => 100, dbic_colname => 'source' } => 'Library' ],
18 );
19 my @select_bind = (
20   [ $attr => 11 ], [ $attr => 12 ], [ $attr => 13 ],
21 );
22 my @group_bind = (
23   [ $attr => 21 ],
24 );
25 my @having_bind = (
26   [ $attr => 31 ],
27 );
28 my @order_bind = (
29   [ $attr => 1 ], [ $attr => 2 ], [ $attr => 3 ],
30 );
31
32 my $tests = {
33
34   LimitOffset => {
35     ordered_limit_offset => [
36       '(
37         SELECT me.id, owner.id, owner.name, ? * ?, ?
38           FROM books me
39           JOIN owners owner
40             ON owner.id = me.owner
41         WHERE source != ? AND me.title = ? AND source = ?
42         GROUP BY avg(me.id / ?)
43         HAVING ?
44         ORDER BY ? / ?, ?
45         LIMIT ?
46         OFFSET ?
47       )',
48       [
49         @select_bind,
50         @where_bind,
51         @group_bind,
52         @having_bind,
53         @order_bind,
54         [ { sqlt_datatype => 'integer' } => 4 ],
55         [ { sqlt_datatype => 'integer' } => 3 ],
56       ],
57     ],
58     limit_offset_prefetch => [
59       '(
60         SELECT me.name, books.id, books.source, books.owner, books.title, books.price
61           FROM (
62             SELECT me.name, me.id
63               FROM owners me
64             LIMIT ? OFFSET ?
65           ) me
66           LEFT JOIN books books
67             ON books.owner = me.id
68         ORDER BY books.owner
69       )',
70       [
71         [ { sqlt_datatype => 'integer' } => 3 ],
72         [ { sqlt_datatype => 'integer' } => 1 ],
73       ]
74     ],
75   },
76
77   LimitXY => {
78     ordered_limit_offset => [
79       '(
80         SELECT me.id, owner.id, owner.name, ? * ?, ?
81           FROM books me
82           JOIN owners owner
83             ON owner.id = me.owner
84         WHERE source != ? AND me.title = ? AND source = ?
85         GROUP BY avg(me.id / ?)
86         HAVING ?
87         ORDER BY ? / ?, ?
88         LIMIT ?, ?
89       )',
90       [
91         @select_bind,
92         @where_bind,
93         @group_bind,
94         @having_bind,
95         @order_bind,
96         [ { sqlt_datatype => 'integer' } => 3 ],
97         [ { sqlt_datatype => 'integer' } => 4 ],
98       ],
99     ],
100     limit_offset_prefetch => [
101       '(
102         SELECT me.name, books.id, books.source, books.owner, books.title, books.price
103           FROM (
104             SELECT me.name, me.id
105               FROM owners me
106             LIMIT ?,?
107           ) me
108           LEFT JOIN books books
109             ON books.owner = me.id
110         ORDER BY books.owner
111       )',
112       [
113         [ { sqlt_datatype => 'integer' } => 1 ],
114         [ { sqlt_datatype => 'integer' } => 3 ],
115       ]
116     ],
117   },
118
119   SkipFirst => {
120     ordered_limit_offset => [
121       '(
122         SELECT SKIP ? FIRST ? me.id, owner.id, owner.name, ? * ?, ?
123           FROM books me
124           JOIN owners owner
125             ON owner.id = me.owner
126         WHERE source != ? AND me.title = ? AND source = ?
127         GROUP BY avg(me.id / ?)
128         HAVING ?
129         ORDER BY ? / ?, ?
130       )',
131       [
132         [ { sqlt_datatype => 'integer' } => 3 ],
133         [ { sqlt_datatype => 'integer' } => 4 ],
134         @select_bind,
135         @where_bind,
136         @group_bind,
137         @having_bind,
138         @order_bind,
139       ],
140     ],
141     limit_offset_prefetch => [
142       '(
143         SELECT me.name, books.id, books.source, books.owner, books.title, books.price
144           FROM (
145             SELECT SKIP ? FIRST ? me.name, me.id
146               FROM owners me
147           ) me
148           LEFT JOIN books books
149             ON books.owner = me.id
150         ORDER BY books.owner
151       )',
152       [
153         [ { sqlt_datatype => 'integer' } => 1 ],
154         [ { sqlt_datatype => 'integer' } => 3 ],
155       ]
156     ],
157   },
158
159   FirstSkip => {
160     ordered_limit_offset => [
161       '(
162         SELECT FIRST ? SKIP ? me.id, owner.id, owner.name, ? * ?, ?
163           FROM books me
164           JOIN owners owner
165             ON owner.id = me.owner
166         WHERE source != ? AND me.title = ? AND source = ?
167         GROUP BY avg(me.id / ?)
168         HAVING ?
169         ORDER BY ? / ?, ?
170       )',
171       [
172         [ { sqlt_datatype => 'integer' } => 4 ],
173         [ { sqlt_datatype => 'integer' } => 3 ],
174         @select_bind,
175         @where_bind,
176         @group_bind,
177         @having_bind,
178         @order_bind,
179       ],
180     ],
181     limit_offset_prefetch => [
182       '(
183         SELECT me.name, books.id, books.source, books.owner, books.title, books.price
184           FROM (
185             SELECT FIRST ? SKIP ? me.name, me.id
186               FROM owners me
187           ) me
188           LEFT JOIN books books
189             ON books.owner = me.id
190         ORDER BY books.owner
191       )',
192       [
193         [ { sqlt_datatype => 'integer' } => 3 ],
194         [ { sqlt_datatype => 'integer' } => 1 ],
195       ]
196     ],
197   },
198
199   RowNumberOver => do {
200     my $unordered_sql = '(
201       SELECT me.id, owner__id, owner__name, bar, baz
202         FROM (
203           SELECT me.id, owner__id, owner__name, bar, baz, ROW_NUMBER() OVER() AS rno__row__index
204             FROM (
205               SELECT me.id, owner.id AS owner__id, owner.name AS owner__name, ? * ? AS bar, ? AS baz
206                 FROM books me
207                 JOIN owners owner
208                   ON owner.id = me.owner
209               WHERE source != ? AND me.title = ? AND source = ?
210               GROUP BY avg(me.id / ?)
211               HAVING ?
212             ) me
213       ) me
214       WHERE rno__row__index >= ? AND rno__row__index <= ?
215     )';
216
217     my $ordered_sql = '(
218       SELECT me.id, owner__id, owner__name, bar, baz
219         FROM (
220           SELECT me.id, owner__id, owner__name, bar, baz, ROW_NUMBER() OVER( ORDER BY ORDER__BY__001, ORDER__BY__002 ) AS rno__row__index
221             FROM (
222               SELECT me.id, owner.id AS owner__id, owner.name AS owner__name, ? * ? AS bar, ? AS baz,
223                      ? / ? AS ORDER__BY__001, ? AS ORDER__BY__002
224                 FROM books me
225                 JOIN owners owner
226                   ON owner.id = me.owner
227               WHERE source != ? AND me.title = ? AND source = ?
228               GROUP BY avg(me.id / ?)
229               HAVING ?
230             ) me
231       ) me
232       WHERE rno__row__index >= ? AND rno__row__index <= ?
233     )';
234
235     {
236       limit => [$unordered_sql,
237         [
238           @select_bind,
239           @where_bind,
240           @group_bind,
241           @having_bind,
242           [ { sqlt_datatype => 'integer' } => 1 ],
243           [ { sqlt_datatype => 'integer' } => 4 ],
244         ],
245       ],
246       limit_offset => [$unordered_sql,
247         [
248           @select_bind,
249           @where_bind,
250           @group_bind,
251           @having_bind,
252           [ { sqlt_datatype => 'integer' } => 4 ],
253           [ { sqlt_datatype => 'integer' } => 7 ],
254         ],
255       ],
256       ordered_limit => [$ordered_sql,
257         [
258           @select_bind,
259           @order_bind,
260           @where_bind,
261           @group_bind,
262           @having_bind,
263           [ { sqlt_datatype => 'integer' } => 1 ],
264           [ { sqlt_datatype => 'integer' } => 4 ],
265         ],
266       ],
267       ordered_limit_offset => [$ordered_sql,
268         [
269           @select_bind,
270           @order_bind,
271           @where_bind,
272           @group_bind,
273           @having_bind,
274           [ { sqlt_datatype => 'integer' } => 4 ],
275           [ { sqlt_datatype => 'integer' } => 7 ],
276         ],
277       ],
278       limit_offset_prefetch => [
279         '(
280           SELECT me.name, books.id, books.source, books.owner, books.title, books.price
281             FROM (
282               SELECT me.name, me.id
283                 FROM (
284                   SELECT me.name, me.id, ROW_NUMBER() OVER() AS rno__row__index
285                   FROM (
286                     SELECT me.name, me.id  FROM owners me
287                   ) me
288                 ) me
289               WHERE rno__row__index >= ? AND rno__row__index <= ?
290             ) me
291             LEFT JOIN books books
292               ON books.owner = me.id
293           ORDER BY books.owner
294         )',
295         [
296           [ { sqlt_datatype => 'integer' } => 2 ],
297           [ { sqlt_datatype => 'integer' } => 4 ],
298         ]
299       ],
300     };
301   },
302
303   RowNum => do {
304     my $limit_sql = sub {
305       sprintf '(
306         SELECT me.id, owner__id, owner__name, bar, baz
307           FROM (
308             SELECT me.id, owner.id AS owner__id, owner.name AS owner__name, ? * ? AS bar, ? AS baz
309               FROM books me
310               JOIN owners owner
311                 ON owner.id = me.owner
312             WHERE source != ? AND me.title = ? AND source = ?
313             GROUP BY avg(me.id / ?)
314             HAVING ?
315             %s
316           ) me
317         WHERE ROWNUM <= ?
318       )', $_[0] || '';
319     };
320
321     {
322       limit => [ $limit_sql->(),
323         [
324           @select_bind,
325           @where_bind,
326           @group_bind,
327           @having_bind,
328           [ { sqlt_datatype => 'integer' } => 4 ],
329         ],
330       ],
331       limit_offset => [
332         '(
333           SELECT me.id, owner__id, owner__name, bar, baz
334             FROM (
335               SELECT me.id, owner__id, owner__name, bar, baz, ROWNUM rownum__index
336                 FROM (
337                   SELECT me.id, owner.id AS owner__id, owner.name AS owner__name, ? * ? AS bar, ? AS baz
338                     FROM books me
339                     JOIN owners owner
340                       ON owner.id = me.owner
341                   WHERE source != ? AND me.title = ? AND source = ?
342                   GROUP BY avg(me.id / ?)
343                   HAVING ?
344                 ) me
345             ) me
346           WHERE rownum__index BETWEEN ? AND ?
347         )',
348         [
349           @select_bind,
350           @where_bind,
351           @group_bind,
352           @having_bind,
353           [ { sqlt_datatype => 'integer' } => 4 ],
354           [ { sqlt_datatype => 'integer' } => 7 ],
355         ],
356       ],
357       ordered_limit => [ $limit_sql->('ORDER BY ? / ?, ?'),
358         [
359           @select_bind,
360           @where_bind,
361           @group_bind,
362           @having_bind,
363           @order_bind,
364           [ { sqlt_datatype => 'integer' } => 4 ],
365         ],
366       ],
367       ordered_limit_offset => [
368         '(
369           SELECT me.id, owner__id, owner__name, bar, baz
370             FROM (
371               SELECT me.id, owner__id, owner__name, bar, baz, ROWNUM rownum__index
372                 FROM (
373                   SELECT me.id, owner.id AS owner__id, owner.name AS owner__name, ? * ? AS bar, ? AS baz
374                     FROM books me
375                     JOIN owners owner
376                       ON owner.id = me.owner
377                   WHERE source != ? AND me.title = ? AND source = ?
378                   GROUP BY avg(me.id / ?)
379                   HAVING ?
380                   ORDER BY ? / ?, ?
381                 ) me
382               WHERE ROWNUM <= ?
383             ) me
384           WHERE rownum__index >= ?
385         )',
386         [
387           @select_bind,
388           @where_bind,
389           @group_bind,
390           @having_bind,
391           @order_bind,
392           [ { sqlt_datatype => 'integer' } => 7 ],
393           [ { sqlt_datatype => 'integer' } => 4 ],
394         ],
395       ],
396       limit_offset_prefetch => [
397         '(
398           SELECT me.name, books.id, books.source, books.owner, books.title, books.price
399             FROM (
400               SELECT me.name, me.id
401                 FROM (
402                   SELECT me.name, me.id, ROWNUM rownum__index
403                     FROM (
404                       SELECT me.name, me.id
405                         FROM owners me
406                     ) me
407                 ) me WHERE rownum__index BETWEEN ? AND ?
408             ) me
409             LEFT JOIN books books
410               ON books.owner = me.id
411           ORDER BY books.owner
412         )',
413         [
414           [ { sqlt_datatype => 'integer' } => 2 ],
415           [ { sqlt_datatype => 'integer' } => 4 ],
416         ]
417       ],
418     };
419   },
420
421   FetchFirst => {
422     limit => [
423       '(
424         SELECT me.id, owner.id, owner.name, ? * ?, ?
425           FROM books me
426           JOIN owners owner
427             ON owner.id = me.owner
428         WHERE source != ? AND me.title = ? AND source = ?
429         GROUP BY avg(me.id / ?)
430         HAVING ?
431         FETCH FIRST 4 ROWS ONLY
432       )',
433       [
434         @select_bind,
435         @where_bind,
436         @group_bind,
437         @having_bind,
438       ],
439     ],
440     limit_offset => [
441       '(
442         SELECT me.id, owner__id, owner__name, bar, baz
443           FROM (
444             SELECT me.id, owner.id AS owner__id, owner.name AS owner__name, ? * ? AS bar, ? AS baz
445               FROM books me
446               JOIN owners owner
447                 ON owner.id = me.owner
448             WHERE source != ? AND me.title = ? AND source = ?
449             GROUP BY avg(me.id / ?)
450             HAVING ?
451             ORDER BY me.id
452             FETCH FIRST 7 ROWS ONLY
453           ) me
454         ORDER BY me.id DESC
455         FETCH FIRST 4 ROWS ONLY
456       )',
457       [
458         @select_bind,
459         @where_bind,
460         @group_bind,
461         @having_bind,
462       ],
463     ],
464     ordered_limit => [
465       '(
466         SELECT me.id, owner.id, owner.name, ? * ?, ?
467           FROM books me
468           JOIN owners owner
469             ON owner.id = me.owner
470         WHERE source != ? AND me.title = ? AND source = ?
471         GROUP BY avg(me.id / ?)
472         HAVING ?
473         ORDER BY ? / ?, ?
474         FETCH FIRST 4 ROWS ONLY
475       )',
476       [
477         @select_bind,
478         @where_bind,
479         @group_bind,
480         @having_bind,
481         @order_bind,
482       ],
483     ],
484     ordered_limit_offset => [
485       '(
486         SELECT me.id, owner__id, owner__name, bar, baz
487           FROM (
488             SELECT me.id, owner__id, owner__name, bar, baz, ORDER__BY__001, ORDER__BY__002
489               FROM (
490                 SELECT me.id, owner.id AS owner__id, owner.name AS owner__name, ? * ? AS bar, ? AS baz, ? / ? AS ORDER__BY__001, ? AS ORDER__BY__002
491                   FROM books me
492                   JOIN owners owner
493                     ON owner.id = me.owner
494                 WHERE source != ? AND me.title = ? AND source = ?
495                 GROUP BY avg(me.id / ?)
496                 HAVING ?
497                 ORDER BY ? / ?, ?
498                 FETCH FIRST 7 ROWS ONLY
499               ) me
500             ORDER BY ORDER__BY__001 DESC, ORDER__BY__002 DESC
501             FETCH FIRST 4 ROWS ONLY
502           ) me
503         ORDER BY ORDER__BY__001, ORDER__BY__002
504       )',
505       [
506         @select_bind,
507         @order_bind,
508         @where_bind,
509         @group_bind,
510         @having_bind,
511         (map { [ @$_ ] } @order_bind),  # without this is_deeply throws a fit
512       ],
513     ],
514     limit_offset_prefetch => [
515       '(
516         SELECT me.name, books.id, books.source, books.owner, books.title, books.price
517           FROM (
518             SELECT me.name, me.id
519               FROM (
520                 SELECT me.name, me.id
521                   FROM owners me
522                 ORDER BY me.id
523                 FETCH FIRST 4 ROWS ONLY
524               ) me
525               ORDER BY me.id DESC
526             FETCH FIRST 3 ROWS ONLY
527           ) me
528           LEFT JOIN books books
529             ON books.owner = me.id
530         ORDER BY books.owner
531       )',
532       [],
533     ],
534   },
535
536   Top => {
537     limit => [
538       '(
539         SELECT TOP 4 me.id, owner.id, owner.name, ? * ?, ?
540           FROM books me
541           JOIN owners owner
542             ON owner.id = me.owner
543         WHERE source != ? AND me.title = ? AND source = ?
544         GROUP BY avg(me.id / ?)
545         HAVING ?
546       )',
547       [
548         @select_bind,
549         @where_bind,
550         @group_bind,
551         @having_bind,
552       ],
553     ],
554     limit_offset => [
555       '(
556         SELECT TOP 4 me.id, owner__id, owner__name, bar, baz
557           FROM (
558             SELECT TOP 7 me.id, owner.id AS owner__id, owner.name AS owner__name, ? * ? AS bar, ? AS baz
559               FROM books me
560               JOIN owners owner
561                 ON owner.id = me.owner
562             WHERE source != ? AND me.title = ? AND source = ?
563             GROUP BY avg(me.id / ?)
564             HAVING ?
565             ORDER BY me.id
566           ) me
567         ORDER BY me.id DESC
568       )',
569       [
570         @select_bind,
571         @where_bind,
572         @group_bind,
573         @having_bind,
574       ],
575     ],
576     ordered_limit => [
577       '(
578         SELECT TOP 4 me.id, owner.id, owner.name, ? * ?, ?
579           FROM books me
580           JOIN owners owner
581             ON owner.id = me.owner
582         WHERE source != ? AND me.title = ? AND source = ?
583         GROUP BY avg(me.id / ?)
584         HAVING ?
585         ORDER BY ? / ?, ?
586       )',
587       [
588         @select_bind,
589         @where_bind,
590         @group_bind,
591         @having_bind,
592         @order_bind,
593       ],
594     ],
595     ordered_limit_offset => [
596       '(
597         SELECT me.id, owner__id, owner__name, bar, baz
598           FROM (
599             SELECT TOP 4 me.id, owner__id, owner__name, bar, baz, ORDER__BY__001, ORDER__BY__002
600               FROM (
601                 SELECT TOP 7 me.id, owner.id AS owner__id, owner.name AS owner__name, ? * ? AS bar, ? AS baz, ? / ? AS ORDER__BY__001, ? AS ORDER__BY__002
602                   FROM books me
603                   JOIN owners owner
604                     ON owner.id = me.owner
605                 WHERE source != ? AND me.title = ? AND source = ?
606                 GROUP BY avg(me.id / ?)
607                 HAVING ?
608                 ORDER BY ? / ?, ?
609               ) me
610             ORDER BY ORDER__BY__001 DESC, ORDER__BY__002 DESC
611           ) me
612         ORDER BY ORDER__BY__001, ORDER__BY__002
613       )',
614       [
615         @select_bind,
616         @order_bind,
617         @where_bind,
618         @group_bind,
619         @having_bind,
620         (map { [ @$_ ] } @order_bind),  # without this is_deeply throws a fit
621       ],
622     ],
623     limit_offset_prefetch => [
624       '(
625         SELECT me.name, books.id, books.source, books.owner, books.title, books.price
626           FROM (
627             SELECT TOP 3 me.name, me.id
628               FROM (
629                 SELECT TOP 4 me.name, me.id
630                   FROM owners me
631                 ORDER BY me.id
632               ) me
633               ORDER BY me.id DESC
634           ) me
635           LEFT JOIN books books
636             ON books.owner = me.id
637         ORDER BY books.owner
638       )',
639       [],
640     ],
641   },
642
643   GenericSubQ => {
644     limit => [
645       '(
646         SELECT me.id, owner__id, owner__name, bar, baz
647           FROM (
648             SELECT me.id, owner.id AS owner__id, owner.name AS owner__name, ? * ? AS bar, ? AS baz
649               FROM books me
650               JOIN owners owner
651                 ON owner.id = me.owner
652             WHERE source != ? AND me.title = ? AND source = ?
653             GROUP BY avg( me.id / ? )
654             HAVING ?
655           ) me
656         WHERE (
657           SELECT COUNT( * )
658             FROM books rownum__emulation
659           WHERE rownum__emulation.id < me.id
660         ) < ?
661         ORDER BY me.id
662       )',
663       [
664         @select_bind,
665         @where_bind,
666         @group_bind,
667         @having_bind,
668         [ { sqlt_datatype => 'integer' } => 4 ],
669       ],
670     ],
671     limit_offset => [
672       '(
673         SELECT me.id, owner__id, owner__name, bar, baz
674           FROM (
675             SELECT me.id, owner.id AS owner__id, owner.name AS owner__name, ? * ? AS bar, ? AS baz
676               FROM books me
677               JOIN owners owner
678                 ON owner.id = me.owner
679             WHERE source != ? AND me.title = ? AND source = ?
680             GROUP BY avg( me.id / ? )
681             HAVING ?
682           ) me
683         WHERE (
684           SELECT COUNT( * )
685             FROM books rownum__emulation
686           WHERE rownum__emulation.id < me.id
687         ) BETWEEN ? AND ?
688         ORDER BY me.id
689       )',
690       [
691         @select_bind,
692         @where_bind,
693         @group_bind,
694         @having_bind,
695         [ { sqlt_datatype => 'integer' } => 3 ],
696         [ { sqlt_datatype => 'integer' } => 6 ],
697       ],
698     ],
699     limit_offset_prefetch => [
700       '(
701         SELECT me.name, books.id, books.source, books.owner, books.title, books.price
702           FROM (
703             SELECT me.name, me.id
704               FROM (
705                 SELECT me.name, me.id  FROM owners me
706               ) me
707             WHERE (
708               SELECT COUNT(*)
709                 FROM owners rownum__emulation
710               WHERE rownum__emulation.id < me.id
711             ) BETWEEN ? AND ?
712             ORDER BY me.id
713           ) me
714           LEFT JOIN books books
715             ON books.owner = me.id
716         ORDER BY me.id, books.owner
717       )',
718       [
719         [ { sqlt_datatype => 'integer' } => 1 ],
720         [ { sqlt_datatype => 'integer' } => 3 ],
721       ],
722     ],
723   }
724 };
725
726 for my $limtype (sort keys %$tests) {
727
728   Test::Builder->new->is_passing or exit;
729
730   delete $schema->storage->_sql_maker->{_cached_syntax};
731   $schema->storage->_sql_maker->limit_dialect ($limtype);
732
733   # chained search is necessary to exercise the recursive {where} parser
734   my $rs = $schema->resultset('BooksInLibrary')->search({ 'me.title' => { '=' => 'kama sutra' } })->search({ source => { '!=', 'Study' } }, {
735     columns => [ { identifier => 'me.id' }, 'owner.id', 'owner.name' ], # people actually do that. BLEH!!! :)
736     join => 'owner',  # single-rel manual prefetch
737     rows => 4,
738     '+columns' => { bar => \['? * ?', [ $attr => 11 ], [ $attr => 12 ]], baz => \[ '?', [ $attr => 13 ]] },
739     group_by => \[ 'avg(me.id / ?)', [ $attr => 21 ] ],
740     having => \[ '?', [ $attr => 31 ] ],
741     ($limtype =~ /GenericSubQ/ ? ( order_by => 'me.id' ) : () ),  # needs a simple-column stable order to be happy
742   });
743
744   #
745   # not all tests run on all dialects (somewhere impossible, somewhere makes no sense)
746   #
747
748   # only limit, no offset, no order
749   is_same_sql_bind(
750     $rs->as_query,
751     @{$tests->{$limtype}{limit}},
752     "$limtype: Unordered limit with select/group/having",
753   ) if $tests->{$limtype}{limit};
754
755   # limit + offset, no order
756   is_same_sql_bind(
757     $rs->search({}, { offset => 3 })->as_query,
758     @{$tests->{$limtype}{limit_offset}},
759     "$limtype: Unordered limit+offset with select/group/having",
760   ) if $tests->{$limtype}{limit_offset};
761
762   # order + limit, no offset
763   $rs = $rs->search(undef, {
764     order_by => [ \['? / ?', [ $attr => 1 ], [ $attr => 2 ]], \[ '?', [ $attr => 3 ]] ],
765   });
766
767   is_same_sql_bind(
768     $rs->as_query,
769     @{$tests->{$limtype}{ordered_limit}},
770     "$limtype: Ordered limit with select/group/having",
771   ) if $tests->{$limtype}{ordered_limit};
772
773   # order + limit + offset
774   is_same_sql_bind(
775     $rs->search({}, { offset => 3 })->as_query,
776     @{$tests->{$limtype}{ordered_limit_offset}},
777     "$limtype: Ordered limit+offset with select/group/having",
778   ) if $tests->{$limtype}{ordered_limit_offset};
779
780   # complex prefetch on partial-fetch root with limit
781   my $pref_rs = $schema->resultset('Owners')->search({}, {
782     rows => 3,
783     offset => 1,
784     columns => 'name',  # only the owner name, still prefetch all the books
785     prefetch => 'books',
786     ($limtype =~ /GenericSubQ/ ? ( order_by => 'me.id' ) : () ),  # needs a simple-column stable order to be happy
787   });
788
789   is_same_sql_bind (
790     $pref_rs->as_query,
791     @{$tests->{$limtype}{limit_offset_prefetch}},
792     "$limtype: Prefetch with limit+offset",
793   ) if $tests->{$limtype}{limit_offset_prefetch};
794
795   # we can actually run the query
796   if ($limtype eq $native_limit_dialect or $limtype eq 'GenericSubQ') {
797     lives_ok { is ($pref_rs->all, 1, 'Expected count of objects on limtied prefetch') }
798       "Complex limited prefetch works with supported limit $limtype"
799   }
800 }
801
802 done_testing;