|
1 # 2001 November 6 |
|
2 # |
|
3 # The author disclaims copyright to this source code. In place of |
|
4 # a legal notice, here is a blessing: |
|
5 # |
|
6 # May you do good and not evil. |
|
7 # May you find forgiveness for yourself and forgive others. |
|
8 # May you share freely, never taking more than you give. |
|
9 # |
|
10 #*********************************************************************** |
|
11 # This file implements regression tests for SQLite library. The |
|
12 # focus of this file is testing the LIMIT ... OFFSET ... clause |
|
13 # of SELECT statements. |
|
14 # |
|
15 # $Id: limit.test,v 1.32 2008/08/02 03:50:39 drh Exp $ |
|
16 |
|
17 set testdir [file dirname $argv0] |
|
18 source $testdir/tester.tcl |
|
19 |
|
20 # Build some test data |
|
21 # |
|
22 execsql { |
|
23 CREATE TABLE t1(x int, y int); |
|
24 BEGIN; |
|
25 } |
|
26 for {set i 1} {$i<=32} {incr i} { |
|
27 for {set j 0} {(1<<$j)<$i} {incr j} {} |
|
28 execsql "INSERT INTO t1 VALUES([expr {32-$i}],[expr {10-$j}])" |
|
29 } |
|
30 execsql { |
|
31 COMMIT; |
|
32 } |
|
33 |
|
34 do_test limit-1.0 { |
|
35 execsql {SELECT count(*) FROM t1} |
|
36 } {32} |
|
37 do_test limit-1.1 { |
|
38 execsql {SELECT count(*) FROM t1 LIMIT 5} |
|
39 } {32} |
|
40 do_test limit-1.2.1 { |
|
41 execsql {SELECT x FROM t1 ORDER BY x LIMIT 5} |
|
42 } {0 1 2 3 4} |
|
43 do_test limit-1.2.2 { |
|
44 execsql {SELECT x FROM t1 ORDER BY x LIMIT 5 OFFSET 2} |
|
45 } {2 3 4 5 6} |
|
46 do_test limit-1.2.3 { |
|
47 execsql {SELECT x FROM t1 ORDER BY x+1 LIMIT 5 OFFSET -2} |
|
48 } {0 1 2 3 4} |
|
49 do_test limit-1.2.4 { |
|
50 execsql {SELECT x FROM t1 ORDER BY x+1 LIMIT 2, -5} |
|
51 } {2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31} |
|
52 do_test limit-1.2.5 { |
|
53 execsql {SELECT x FROM t1 ORDER BY x+1 LIMIT -2, 5} |
|
54 } {0 1 2 3 4} |
|
55 do_test limit-1.2.6 { |
|
56 execsql {SELECT x FROM t1 ORDER BY x+1 LIMIT -2, -5} |
|
57 } {0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31} |
|
58 do_test limit-1.2.7 { |
|
59 execsql {SELECT x FROM t1 ORDER BY x LIMIT 2, 5} |
|
60 } {2 3 4 5 6} |
|
61 do_test limit-1.3 { |
|
62 execsql {SELECT x FROM t1 ORDER BY x LIMIT 5 OFFSET 5} |
|
63 } {5 6 7 8 9} |
|
64 do_test limit-1.4.1 { |
|
65 execsql {SELECT x FROM t1 ORDER BY x LIMIT 50 OFFSET 30} |
|
66 } {30 31} |
|
67 do_test limit-1.4.2 { |
|
68 execsql {SELECT x FROM t1 ORDER BY x LIMIT 30, 50} |
|
69 } {30 31} |
|
70 do_test limit-1.5 { |
|
71 execsql {SELECT x FROM t1 ORDER BY x LIMIT 50 OFFSET 50} |
|
72 } {} |
|
73 do_test limit-1.6 { |
|
74 execsql {SELECT * FROM t1 AS a, t1 AS b ORDER BY a.x, b.x LIMIT 5} |
|
75 } {0 5 0 5 0 5 1 5 0 5 2 5 0 5 3 5 0 5 4 5} |
|
76 do_test limit-1.7 { |
|
77 execsql {SELECT * FROM t1 AS a, t1 AS b ORDER BY a.x, b.x LIMIT 5 OFFSET 32} |
|
78 } {1 5 0 5 1 5 1 5 1 5 2 5 1 5 3 5 1 5 4 5} |
|
79 |
|
80 ifcapable {view && subquery} { |
|
81 do_test limit-2.1 { |
|
82 execsql { |
|
83 CREATE VIEW v1 AS SELECT * FROM t1 LIMIT 2; |
|
84 SELECT count(*) FROM (SELECT * FROM v1); |
|
85 } |
|
86 } 2 |
|
87 } ;# ifcapable view |
|
88 do_test limit-2.2 { |
|
89 execsql { |
|
90 CREATE TABLE t2 AS SELECT * FROM t1 LIMIT 2; |
|
91 SELECT count(*) FROM t2; |
|
92 } |
|
93 } 2 |
|
94 ifcapable subquery { |
|
95 do_test limit-2.3 { |
|
96 execsql { |
|
97 SELECT count(*) FROM t1 WHERE rowid IN (SELECT rowid FROM t1 LIMIT 2); |
|
98 } |
|
99 } 2 |
|
100 } |
|
101 |
|
102 ifcapable subquery { |
|
103 do_test limit-3.1 { |
|
104 execsql { |
|
105 SELECT z FROM (SELECT y*10+x AS z FROM t1 ORDER BY x LIMIT 10) |
|
106 ORDER BY z LIMIT 5; |
|
107 } |
|
108 } {50 51 52 53 54} |
|
109 } |
|
110 |
|
111 do_test limit-4.1 { |
|
112 ifcapable subquery { |
|
113 execsql { |
|
114 BEGIN; |
|
115 CREATE TABLE t3(x); |
|
116 INSERT INTO t3 SELECT x FROM t1 ORDER BY x LIMIT 10 OFFSET 1; |
|
117 INSERT INTO t3 SELECT x+(SELECT max(x) FROM t3) FROM t3; |
|
118 INSERT INTO t3 SELECT x+(SELECT max(x) FROM t3) FROM t3; |
|
119 INSERT INTO t3 SELECT x+(SELECT max(x) FROM t3) FROM t3; |
|
120 INSERT INTO t3 SELECT x+(SELECT max(x) FROM t3) FROM t3; |
|
121 INSERT INTO t3 SELECT x+(SELECT max(x) FROM t3) FROM t3; |
|
122 INSERT INTO t3 SELECT x+(SELECT max(x) FROM t3) FROM t3; |
|
123 INSERT INTO t3 SELECT x+(SELECT max(x) FROM t3) FROM t3; |
|
124 INSERT INTO t3 SELECT x+(SELECT max(x) FROM t3) FROM t3; |
|
125 INSERT INTO t3 SELECT x+(SELECT max(x) FROM t3) FROM t3; |
|
126 INSERT INTO t3 SELECT x+(SELECT max(x) FROM t3) FROM t3; |
|
127 END; |
|
128 SELECT count(*) FROM t3; |
|
129 } |
|
130 } else { |
|
131 execsql { |
|
132 BEGIN; |
|
133 CREATE TABLE t3(x); |
|
134 INSERT INTO t3 SELECT x FROM t1 ORDER BY x LIMIT 10 OFFSET 1; |
|
135 } |
|
136 for {set i 0} {$i<10} {incr i} { |
|
137 set max_x_t3 [execsql {SELECT max(x) FROM t3}] |
|
138 execsql "INSERT INTO t3 SELECT x+$max_x_t3 FROM t3;" |
|
139 } |
|
140 execsql { |
|
141 END; |
|
142 SELECT count(*) FROM t3; |
|
143 } |
|
144 } |
|
145 } {10240} |
|
146 do_test limit-4.2 { |
|
147 execsql { |
|
148 SELECT x FROM t3 LIMIT 2 OFFSET 10000 |
|
149 } |
|
150 } {10001 10002} |
|
151 do_test limit-4.3 { |
|
152 execsql { |
|
153 CREATE TABLE t4 AS SELECT x, |
|
154 'abcdefghijklmnopqrstuvwyxz ABCDEFGHIJKLMNOPQRSTUVWYXZ' || x || |
|
155 'abcdefghijklmnopqrstuvwyxz ABCDEFGHIJKLMNOPQRSTUVWYXZ' || x || |
|
156 'abcdefghijklmnopqrstuvwyxz ABCDEFGHIJKLMNOPQRSTUVWYXZ' || x || |
|
157 'abcdefghijklmnopqrstuvwyxz ABCDEFGHIJKLMNOPQRSTUVWYXZ' || x || |
|
158 'abcdefghijklmnopqrstuvwyxz ABCDEFGHIJKLMNOPQRSTUVWYXZ' || x AS y |
|
159 FROM t3 LIMIT 1000; |
|
160 SELECT x FROM t4 ORDER BY y DESC LIMIT 1 OFFSET 999; |
|
161 } |
|
162 } {1000} |
|
163 |
|
164 do_test limit-5.1 { |
|
165 execsql { |
|
166 CREATE TABLE t5(x,y); |
|
167 INSERT INTO t5 SELECT x-y, x+y FROM t1 WHERE x BETWEEN 10 AND 15 |
|
168 ORDER BY x LIMIT 2; |
|
169 SELECT * FROM t5 ORDER BY x; |
|
170 } |
|
171 } {5 15 6 16} |
|
172 do_test limit-5.2 { |
|
173 execsql { |
|
174 DELETE FROM t5; |
|
175 INSERT INTO t5 SELECT x-y, x+y FROM t1 WHERE x BETWEEN 10 AND 15 |
|
176 ORDER BY x DESC LIMIT 2; |
|
177 SELECT * FROM t5 ORDER BY x; |
|
178 } |
|
179 } {9 19 10 20} |
|
180 do_test limit-5.3 { |
|
181 execsql { |
|
182 DELETE FROM t5; |
|
183 INSERT INTO t5 SELECT x-y, x+y FROM t1 WHERE x ORDER BY x DESC LIMIT 31; |
|
184 SELECT * FROM t5 ORDER BY x LIMIT 2; |
|
185 } |
|
186 } {-4 6 -3 7} |
|
187 do_test limit-5.4 { |
|
188 execsql { |
|
189 SELECT * FROM t5 ORDER BY x DESC, y DESC LIMIT 2; |
|
190 } |
|
191 } {21 41 21 39} |
|
192 do_test limit-5.5 { |
|
193 execsql { |
|
194 DELETE FROM t5; |
|
195 INSERT INTO t5 SELECT a.x*100+b.x, a.y*100+b.y FROM t1 AS a, t1 AS b |
|
196 ORDER BY 1, 2 LIMIT 1000; |
|
197 SELECT count(*), sum(x), sum(y), min(x), max(x), min(y), max(y) FROM t5; |
|
198 } |
|
199 } {1000 1528204 593161 0 3107 505 1005} |
|
200 |
|
201 # There is some contraversy about whether LIMIT 0 should be the same as |
|
202 # no limit at all or if LIMIT 0 should result in zero output rows. |
|
203 # |
|
204 do_test limit-6.1 { |
|
205 execsql { |
|
206 BEGIN; |
|
207 CREATE TABLE t6(a); |
|
208 INSERT INTO t6 VALUES(1); |
|
209 INSERT INTO t6 VALUES(2); |
|
210 INSERT INTO t6 SELECT a+2 FROM t6; |
|
211 COMMIT; |
|
212 SELECT * FROM t6; |
|
213 } |
|
214 } {1 2 3 4} |
|
215 do_test limit-6.2 { |
|
216 execsql { |
|
217 SELECT * FROM t6 LIMIT -1 OFFSET -1; |
|
218 } |
|
219 } {1 2 3 4} |
|
220 do_test limit-6.3 { |
|
221 execsql { |
|
222 SELECT * FROM t6 LIMIT 2 OFFSET -123; |
|
223 } |
|
224 } {1 2} |
|
225 do_test limit-6.4 { |
|
226 execsql { |
|
227 SELECT * FROM t6 LIMIT -432 OFFSET 2; |
|
228 } |
|
229 } {3 4} |
|
230 do_test limit-6.5 { |
|
231 execsql { |
|
232 SELECT * FROM t6 LIMIT -1 |
|
233 } |
|
234 } {1 2 3 4} |
|
235 do_test limit-6.6 { |
|
236 execsql { |
|
237 SELECT * FROM t6 LIMIT -1 OFFSET 1 |
|
238 } |
|
239 } {2 3 4} |
|
240 do_test limit-6.7 { |
|
241 execsql { |
|
242 SELECT * FROM t6 LIMIT 0 |
|
243 } |
|
244 } {} |
|
245 do_test limit-6.8 { |
|
246 execsql { |
|
247 SELECT * FROM t6 LIMIT 0 OFFSET 1 |
|
248 } |
|
249 } {} |
|
250 |
|
251 # Make sure LIMIT works well with compound SELECT statements. |
|
252 # Ticket #393 |
|
253 # |
|
254 ifcapable compound { |
|
255 do_test limit-7.1.1 { |
|
256 catchsql { |
|
257 SELECT x FROM t2 LIMIT 5 UNION ALL SELECT a FROM t6; |
|
258 } |
|
259 } {1 {LIMIT clause should come after UNION ALL not before}} |
|
260 do_test limit-7.1.2 { |
|
261 catchsql { |
|
262 SELECT x FROM t2 LIMIT 5 UNION SELECT a FROM t6; |
|
263 } |
|
264 } {1 {LIMIT clause should come after UNION not before}} |
|
265 do_test limit-7.1.3 { |
|
266 catchsql { |
|
267 SELECT x FROM t2 LIMIT 5 EXCEPT SELECT a FROM t6 LIMIT 3; |
|
268 } |
|
269 } {1 {LIMIT clause should come after EXCEPT not before}} |
|
270 do_test limit-7.1.4 { |
|
271 catchsql { |
|
272 SELECT x FROM t2 LIMIT 0,5 INTERSECT SELECT a FROM t6; |
|
273 } |
|
274 } {1 {LIMIT clause should come after INTERSECT not before}} |
|
275 do_test limit-7.2 { |
|
276 execsql { |
|
277 SELECT x FROM t2 UNION ALL SELECT a FROM t6 LIMIT 5; |
|
278 } |
|
279 } {31 30 1 2 3} |
|
280 do_test limit-7.3 { |
|
281 execsql { |
|
282 SELECT x FROM t2 UNION ALL SELECT a FROM t6 LIMIT 3 OFFSET 1; |
|
283 } |
|
284 } {30 1 2} |
|
285 do_test limit-7.4 { |
|
286 execsql { |
|
287 SELECT x FROM t2 UNION ALL SELECT a FROM t6 ORDER BY 1 LIMIT 3 OFFSET 1; |
|
288 } |
|
289 } {2 3 4} |
|
290 do_test limit-7.5 { |
|
291 execsql { |
|
292 SELECT x FROM t2 UNION SELECT x+2 FROM t2 LIMIT 2 OFFSET 1; |
|
293 } |
|
294 } {31 32} |
|
295 do_test limit-7.6 { |
|
296 execsql { |
|
297 SELECT x FROM t2 UNION SELECT x+2 FROM t2 ORDER BY 1 DESC LIMIT 2 OFFSET 1; |
|
298 } |
|
299 } {32 31} |
|
300 do_test limit-7.7 { |
|
301 execsql { |
|
302 SELECT a+9 FROM t6 EXCEPT SELECT y FROM t2 LIMIT 2; |
|
303 } |
|
304 } {11 12} |
|
305 do_test limit-7.8 { |
|
306 execsql { |
|
307 SELECT a+9 FROM t6 EXCEPT SELECT y FROM t2 ORDER BY 1 DESC LIMIT 2; |
|
308 } |
|
309 } {13 12} |
|
310 do_test limit-7.9 { |
|
311 execsql { |
|
312 SELECT a+26 FROM t6 INTERSECT SELECT x FROM t2 LIMIT 1; |
|
313 } |
|
314 } {30} |
|
315 do_test limit-7.10 { |
|
316 execsql { |
|
317 SELECT a+27 FROM t6 INTERSECT SELECT x FROM t2 LIMIT 1; |
|
318 } |
|
319 } {30} |
|
320 do_test limit-7.11 { |
|
321 execsql { |
|
322 SELECT a+27 FROM t6 INTERSECT SELECT x FROM t2 LIMIT 1 OFFSET 1; |
|
323 } |
|
324 } {31} |
|
325 do_test limit-7.12 { |
|
326 execsql { |
|
327 SELECT a+27 FROM t6 INTERSECT SELECT x FROM t2 |
|
328 ORDER BY 1 DESC LIMIT 1 OFFSET 1; |
|
329 } |
|
330 } {30} |
|
331 } ;# ifcapable compound |
|
332 |
|
333 # Tests for limit in conjunction with distinct. The distinct should |
|
334 # occur before both the limit and the offset. Ticket #749. |
|
335 # |
|
336 do_test limit-8.1 { |
|
337 execsql { |
|
338 SELECT DISTINCT cast(round(x/100) as integer) FROM t3 LIMIT 5; |
|
339 } |
|
340 } {0 1 2 3 4} |
|
341 do_test limit-8.2 { |
|
342 execsql { |
|
343 SELECT DISTINCT cast(round(x/100) as integer) FROM t3 LIMIT 5 OFFSET 5; |
|
344 } |
|
345 } {5 6 7 8 9} |
|
346 do_test limit-8.3 { |
|
347 execsql { |
|
348 SELECT DISTINCT cast(round(x/100) as integer) FROM t3 LIMIT 5 OFFSET 25; |
|
349 } |
|
350 } {25 26 27 28 29} |
|
351 |
|
352 # Make sure limits on multiple subqueries work correctly. |
|
353 # Ticket #1035 |
|
354 # |
|
355 ifcapable subquery { |
|
356 do_test limit-9.1 { |
|
357 execsql { |
|
358 SELECT * FROM (SELECT * FROM t6 LIMIT 3); |
|
359 } |
|
360 } {1 2 3} |
|
361 } |
|
362 do_test limit-9.2.1 { |
|
363 execsql { |
|
364 CREATE TABLE t7 AS SELECT * FROM t6; |
|
365 } |
|
366 } {} |
|
367 ifcapable subquery { |
|
368 do_test limit-9.2.2 { |
|
369 execsql { |
|
370 SELECT * FROM (SELECT * FROM t7 LIMIT 3); |
|
371 } |
|
372 } {1 2 3} |
|
373 } |
|
374 ifcapable compound { |
|
375 ifcapable subquery { |
|
376 do_test limit-9.3 { |
|
377 execsql { |
|
378 SELECT * FROM (SELECT * FROM t6 LIMIT 3) |
|
379 UNION |
|
380 SELECT * FROM (SELECT * FROM t7 LIMIT 3) |
|
381 ORDER BY 1 |
|
382 } |
|
383 } {1 2 3} |
|
384 do_test limit-9.4 { |
|
385 execsql { |
|
386 SELECT * FROM (SELECT * FROM t6 LIMIT 3) |
|
387 UNION |
|
388 SELECT * FROM (SELECT * FROM t7 LIMIT 3) |
|
389 ORDER BY 1 |
|
390 LIMIT 2 |
|
391 } |
|
392 } {1 2} |
|
393 } |
|
394 do_test limit-9.5 { |
|
395 catchsql { |
|
396 SELECT * FROM t6 LIMIT 3 |
|
397 UNION |
|
398 SELECT * FROM t7 LIMIT 3 |
|
399 } |
|
400 } {1 {LIMIT clause should come after UNION not before}} |
|
401 } |
|
402 |
|
403 # Test LIMIT and OFFSET using SQL variables. |
|
404 do_test limit-10.1 { |
|
405 set limit 10 |
|
406 db eval { |
|
407 SELECT x FROM t1 LIMIT :limit; |
|
408 } |
|
409 } {31 30 29 28 27 26 25 24 23 22} |
|
410 do_test limit-10.2 { |
|
411 set limit 5 |
|
412 set offset 5 |
|
413 db eval { |
|
414 SELECT x FROM t1 LIMIT :limit OFFSET :offset; |
|
415 } |
|
416 } {26 25 24 23 22} |
|
417 do_test limit-10.3 { |
|
418 set limit -1 |
|
419 db eval { |
|
420 SELECT x FROM t1 WHERE x<10 LIMIT :limit; |
|
421 } |
|
422 } {9 8 7 6 5 4 3 2 1 0} |
|
423 do_test limit-10.4 { |
|
424 set limit 1.5 |
|
425 set rc [catch { |
|
426 db eval { |
|
427 SELECT x FROM t1 WHERE x<10 LIMIT :limit; |
|
428 } } msg] |
|
429 list $rc $msg |
|
430 } {1 {datatype mismatch}} |
|
431 do_test limit-10.5 { |
|
432 set limit "hello world" |
|
433 set rc [catch { |
|
434 db eval { |
|
435 SELECT x FROM t1 WHERE x<10 LIMIT :limit; |
|
436 } } msg] |
|
437 list $rc $msg |
|
438 } {1 {datatype mismatch}} |
|
439 |
|
440 ifcapable subquery { |
|
441 do_test limit-11.1 { |
|
442 db eval { |
|
443 SELECT x FROM (SELECT x FROM t1 ORDER BY x LIMIT 0) ORDER BY x |
|
444 } |
|
445 } {} |
|
446 } ;# ifcapable subquery |
|
447 |
|
448 # Test error processing. |
|
449 # |
|
450 do_test limit-12.1 { |
|
451 catchsql { |
|
452 SELECT * FROM t1 LIMIT replace(1) |
|
453 } |
|
454 } {1 {wrong number of arguments to function replace()}} |
|
455 do_test limit-12.2 { |
|
456 catchsql { |
|
457 SELECT * FROM t1 LIMIT 5 OFFSET replace(1) |
|
458 } |
|
459 } {1 {wrong number of arguments to function replace()}} |
|
460 do_test limit-12.3 { |
|
461 catchsql { |
|
462 SELECT * FROM t1 LIMIT x |
|
463 } |
|
464 } {1 {no such column: x}} |
|
465 do_test limit-12.4 { |
|
466 catchsql { |
|
467 SELECT * FROM t1 LIMIT 1 OFFSET x |
|
468 } |
|
469 } {1 {no such column: x}} |
|
470 |
|
471 |
|
472 finish_test |