1 # Test to ensure we get a consistent result set wether or not we use the
2 # prefetch option in combination rows (LIMIT).
9 use DBICTest ':DiffSQL';
10 use DBIx::Class::SQLMaker::LimitDialects;
12 my $ROWS = DBIx::Class::SQLMaker::LimitDialects->__rows_bindtype;
14 my $schema = DBICTest->init_schema();
17 my $no_prefetch = $schema->resultset('Artist')->search(
18 [ # search deliberately contrived
19 { 'artwork.cd_id' => undef },
20 { 'tracks.title' => { '!=' => 'blah-blah-1234568' }}
22 { rows => 3, join => { cds => [qw/artwork tracks/] },
26 my $use_prefetch = $no_prefetch->search(
29 select => ['me.artistid', 'me.name'],
30 as => ['artistid', 'name'],
32 order_by => { -desc => 'name' },
36 # add an extra +select to make sure it does not throw things off
37 # we also expect it to appear in both selectors, as we can not know
38 # for sure which part of the query it applies to (may be order_by,
39 # maybe something else)
41 # we use a reference to the same array in bind vals, because
42 # is_deeply picks up this difference too (not sure if bug or
44 $use_prefetch = $use_prefetch->search({}, {
45 '+columns' => { monkeywrench => \[ 'me.artistid + ?', [ \ 'inTEger' => 1 ] ] },
48 my $bind_int_resolved = sub { [ { sqlt_datatype => 'inTEger' } => 1 ] };
49 my $bind_vc_resolved = sub { [
50 { sqlt_datatype => 'varchar', sqlt_size => 100, dbic_colname => 'tracks.title' }
51 => 'blah-blah-1234568'
54 $use_prefetch->as_query,
56 SELECT me.artistid + ?,
58 cds.cdid, cds.artist, cds.title, cds.year, cds.genreid, cds.single_track
60 SELECT me.artistid + ?,
64 ON cds.artist = me.artistid
65 LEFT JOIN cd_artwork artwork
66 ON artwork.cd_id = cds.cdid
67 LEFT JOIN track tracks
68 ON tracks.cd = cds.cdid
69 WHERE artwork.cd_id IS NULL
71 GROUP BY me.artistid + ?, me.artistid, me.name
72 ORDER BY name DESC LIMIT ?
75 ON cds.artist = me.artistid
76 LEFT JOIN cd_artwork artwork
77 ON artwork.cd_id = cds.cdid
78 LEFT JOIN track tracks
79 ON tracks.cd = cds.cdid
80 WHERE artwork.cd_id IS NULL
85 $bind_int_resolved->(), # outer select
86 $bind_int_resolved->(), # inner select
87 $bind_vc_resolved->(), # inner where
88 $bind_int_resolved->(), # inner group_by
90 $bind_vc_resolved->(), # outer where
92 'Expected SQL on complex limited prefetch'
95 is($no_prefetch->count, $use_prefetch->count, '$no_prefetch->count == $use_prefetch->count');
97 scalar ($no_prefetch->all),
98 scalar ($use_prefetch->all),
99 "Amount of returned rows is right"
102 my $artist_many_cds = $schema->resultset('Artist')->search ( {}, {
104 group_by => 'me.artistid',
105 having => \ 'count(cds.cdid) > 1',
109 $no_prefetch = $schema->resultset('Artist')->search(
110 { artistid => $artist_many_cds->id },
114 $use_prefetch = $no_prefetch->search ({}, { prefetch => 'cds' });
116 my $normal_artist = $no_prefetch->single;
117 my $prefetch_artist = $use_prefetch->find({ name => $artist_many_cds->name });
118 my $prefetch2_artist = $use_prefetch->first;
121 $prefetch_artist->cds->count,
122 $normal_artist->cds->count,
123 "Count of child rel with prefetch + rows => 1 is right (find)"
126 $prefetch2_artist->cds->count,
127 $normal_artist->cds->count,
128 "Count of child rel with prefetch + rows => 1 is right (first)"
132 scalar ($prefetch_artist->cds->all),
133 scalar ($normal_artist->cds->all),
134 "Amount of child rel rows with prefetch + rows => 1 is right (find)"
137 scalar ($prefetch2_artist->cds->all),
138 scalar ($normal_artist->cds->all),
139 "Amount of child rel rows with prefetch + rows => 1 is right (first)"
143 sub { $use_prefetch->single },
144 qr/\Qsingle() can not be used on resultsets collapsing a has_many/,
145 'single() with multiprefetch is illegal',
150 $use_prefetch->search(
151 {'tracks.title' => { '!=' => 'foo' }},
152 { order_by => \ 'some oddball literal sql', join => { cds => 'tracks' } }
154 }, qr/Unable to programatically derive a required group_by from the supplied order_by criteria/,
157 my $artist = $use_prefetch->search({'cds.title' => $artist_many_cds->cds->first->title })->next;
158 is($artist->cds->count, 1, "count on search limiting prefetched has_many");
160 # try with double limit
161 my $artist2 = $use_prefetch->search({'cds.title' => { '!=' => $artist_many_cds->cds->first->title } })->slice (0,0)->next;
162 is($artist2->cds->count, 2, "count on search limiting prefetched has_many");
164 # make sure 1:1 joins do not force a subquery (no point to exercise the optimizer, if at all available)
165 # get cd's that have any tracks and their artists
166 my $single_prefetch_rs = $schema->resultset ('CD')->search (
167 { 'me.year' => 2010, 'artist.name' => 'foo' },
168 { prefetch => ['tracks', 'artist'], rows => 15 },
171 $single_prefetch_rs->as_query,
174 me.cdid, me.artist, me.title, me.year, me.genreid, me.single_track,
175 tracks.trackid, tracks.cd, tracks.position, tracks.title, tracks.last_updated_on, tracks.last_updated_at,
176 artist.artistid, artist.name, artist.rank, artist.charfield
179 me.cdid, me.artist, me.title, me.year, me.genreid, me.single_track
181 JOIN artist artist ON artist.artistid = me.artist
182 WHERE ( ( artist.name = ? AND me.year = ? ) )
185 LEFT JOIN track tracks
186 ON tracks.cd = me.cdid
188 ON artist.artistid = me.artist
189 WHERE ( ( artist.name = ? AND me.year = ? ) )
192 [ { sqlt_datatype => 'varchar', sqlt_size => 100, dbic_colname => 'artist.name' } => 'foo' ],
193 [ { sqlt_datatype => 'varchar', sqlt_size => 100, dbic_colname => 'me.year' } => 2010 ],
195 [ { sqlt_datatype => 'varchar', sqlt_size => 100, dbic_colname => 'artist.name' } => 'foo' ],
196 [ { sqlt_datatype => 'varchar', sqlt_size => 100, dbic_colname => 'me.year' } => 2010 ],
198 'No grouping of non-multiplying resultsets',
201 my $many_one_many_rs = $schema->resultset('CD')->search({}, {
202 prefetch => { tracks => { lyrics => 'lyric_versions' } },
204 order_by => ['lyrics.track_id'],
208 $many_one_many_rs->as_query,
210 SELECT me.cdid, me.artist, me.title, me.year, me.genreid, me.single_track,
211 tracks.trackid, tracks.cd, tracks.position, tracks.title, tracks.last_updated_on, tracks.last_updated_at,
212 lyrics.lyric_id, lyrics.track_id, lyric_versions.id, lyric_versions.lyric_id, lyric_versions.text
214 SELECT me.cdid, me.artist, me.title, me.year, me.genreid, me.single_track
216 LEFT JOIN track tracks
217 ON tracks.cd = me.cdid
218 LEFT JOIN lyrics lyrics
219 ON lyrics.track_id = tracks.trackid
220 GROUP BY me.cdid, me.artist, me.title, me.year, me.genreid, me.single_track
221 ORDER BY MIN(lyrics.track_id)
224 LEFT JOIN track tracks
225 ON tracks.cd = me.cdid
226 LEFT JOIN lyrics lyrics
227 ON lyrics.track_id = tracks.trackid
228 LEFT JOIN lyric_versions lyric_versions
229 ON lyric_versions.lyric_id = lyrics.lyric_id
230 ORDER BY lyrics.track_id
233 [ { sqlt_datatype => 'integer' } => 2 ]
235 'Correct SQL on indirectly multiplied orderer',
238 my $cond_on_multi_ord_by_single = $schema->resultset('CD')->search(
240 'tracks.position' => { '!=', 1 },
243 prefetch => [qw( tracks artist )],
244 order_by => 'artist.name',
250 $cond_on_multi_ord_by_single->as_query,
252 SELECT me.cdid, me.artist, me.title, me.year, me.genreid, me.single_track,
253 tracks.trackid, tracks.cd, tracks.position, tracks.title, tracks.last_updated_on, tracks.last_updated_at,
254 artist.artistid, artist.name, artist.rank, artist.charfield
256 SELECT me.cdid, me.artist, me.title, me.year, me.genreid, me.single_track
258 LEFT JOIN track tracks
259 ON tracks.cd = me.cdid
261 ON artist.artistid = me.artist
262 WHERE tracks.position != ?
263 GROUP BY me.cdid, me.artist, me.title, me.year, me.genreid, me.single_track, artist.name
267 LEFT JOIN track tracks
268 ON tracks.cd = me.cdid
270 ON artist.artistid = me.artist
271 WHERE tracks.position != ?
275 [ { dbic_colname => "tracks.position", sqlt_datatype => "int" }
278 [ { sqlt_datatype => "integer" }
281 [ { dbic_colname => "tracks.position", sqlt_datatype => "int" }
285 'Correct SQl on prefetch with limit of restricting multi ordered by a single'