Annotation of embedaddon/sqlite3/test/subquery.test, revision 1.1.1.1
1.1 misho 1: # 2005 January 19
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 script is testing correlated subqueries
13: #
14: # $Id: subquery.test,v 1.17 2009/01/09 01:12:28 drh Exp $
15: #
16:
17: set testdir [file dirname $argv0]
18: source $testdir/tester.tcl
19:
20: ifcapable !subquery {
21: finish_test
22: return
23: }
24:
25: do_test subquery-1.1 {
26: execsql {
27: BEGIN;
28: CREATE TABLE t1(a,b);
29: INSERT INTO t1 VALUES(1,2);
30: INSERT INTO t1 VALUES(3,4);
31: INSERT INTO t1 VALUES(5,6);
32: INSERT INTO t1 VALUES(7,8);
33: CREATE TABLE t2(x,y);
34: INSERT INTO t2 VALUES(1,1);
35: INSERT INTO t2 VALUES(3,9);
36: INSERT INTO t2 VALUES(5,25);
37: INSERT INTO t2 VALUES(7,49);
38: COMMIT;
39: }
40: execsql {
41: SELECT a, (SELECT y FROM t2 WHERE x=a) FROM t1 WHERE b<8
42: }
43: } {1 1 3 9 5 25}
44: do_test subquery-1.2 {
45: execsql {
46: UPDATE t1 SET b=b+(SELECT y FROM t2 WHERE x=a);
47: SELECT * FROM t1;
48: }
49: } {1 3 3 13 5 31 7 57}
50:
51: do_test subquery-1.3 {
52: execsql {
53: SELECT b FROM t1 WHERE EXISTS(SELECT * FROM t2 WHERE y=a)
54: }
55: } {3}
56: do_test subquery-1.4 {
57: execsql {
58: SELECT b FROM t1 WHERE NOT EXISTS(SELECT * FROM t2 WHERE y=a)
59: }
60: } {13 31 57}
61:
62: # Simple tests to make sure correlated subqueries in WHERE clauses
63: # are used by the query optimizer correctly.
64: do_test subquery-1.5 {
65: execsql {
66: SELECT a, x FROM t1, t2 WHERE t1.a = (SELECT x);
67: }
68: } {1 1 3 3 5 5 7 7}
69: do_test subquery-1.6 {
70: execsql {
71: CREATE INDEX i1 ON t1(a);
72: SELECT a, x FROM t1, t2 WHERE t1.a = (SELECT x);
73: }
74: } {1 1 3 3 5 5 7 7}
75: do_test subquery-1.7 {
76: execsql {
77: SELECT a, x FROM t2, t1 WHERE t1.a = (SELECT x);
78: }
79: } {1 1 3 3 5 5 7 7}
80:
81: # Try an aggregate in both the subquery and the parent query.
82: do_test subquery-1.8 {
83: execsql {
84: SELECT count(*) FROM t1 WHERE a > (SELECT count(*) FROM t2);
85: }
86: } {2}
87:
88: # Test a correlated subquery disables the "only open the index" optimization.
89: do_test subquery-1.9.1 {
90: execsql {
91: SELECT (y*2)>b FROM t1, t2 WHERE a=x;
92: }
93: } {0 1 1 1}
94: do_test subquery-1.9.2 {
95: execsql {
96: SELECT a FROM t1 WHERE (SELECT (y*2)>b FROM t2 WHERE a=x);
97: }
98: } {3 5 7}
99:
100: # Test that the flattening optimization works with subquery expressions.
101: do_test subquery-1.10.1 {
102: execsql {
103: SELECT (SELECT a), b FROM t1;
104: }
105: } {1 3 3 13 5 31 7 57}
106: do_test subquery-1.10.2 {
107: execsql {
108: SELECT * FROM (SELECT (SELECT a), b FROM t1);
109: }
110: } {1 3 3 13 5 31 7 57}
111: do_test subquery-1.10.3 {
112: execsql {
113: SELECT * FROM (SELECT (SELECT sum(a) FROM t1));
114: }
115: } {16}
116: do_test subquery-1.10.4 {
117: execsql {
118: CREATE TABLE t5 (val int, period text PRIMARY KEY);
119: INSERT INTO t5 VALUES(5, '2001-3');
120: INSERT INTO t5 VALUES(10, '2001-4');
121: INSERT INTO t5 VALUES(15, '2002-1');
122: INSERT INTO t5 VALUES(5, '2002-2');
123: INSERT INTO t5 VALUES(10, '2002-3');
124: INSERT INTO t5 VALUES(15, '2002-4');
125: INSERT INTO t5 VALUES(10, '2003-1');
126: INSERT INTO t5 VALUES(5, '2003-2');
127: INSERT INTO t5 VALUES(25, '2003-3');
128: INSERT INTO t5 VALUES(5, '2003-4');
129:
130: SELECT period, vsum
131: FROM (SELECT
132: a.period,
133: (select sum(val) from t5 where period between a.period and '2002-4') vsum
134: FROM t5 a where a.period between '2002-1' and '2002-4')
135: WHERE vsum < 45 ;
136: }
137: } {2002-2 30 2002-3 25 2002-4 15}
138: do_test subquery-1.10.5 {
139: execsql {
140: SELECT period, vsum from
141: (select a.period,
142: (select sum(val) from t5 where period between a.period and '2002-4') vsum
143: FROM t5 a where a.period between '2002-1' and '2002-4')
144: WHERE vsum < 45 ;
145: }
146: } {2002-2 30 2002-3 25 2002-4 15}
147: do_test subquery-1.10.6 {
148: execsql {
149: DROP TABLE t5;
150: }
151: } {}
152:
153:
154:
155: #------------------------------------------------------------------
156: # The following test cases - subquery-2.* - are not logically
157: # organized. They're here largely because they were failing during
158: # one stage of development of sub-queries.
159: #
160: do_test subquery-2.1 {
161: execsql {
162: SELECT (SELECT 10);
163: }
164: } {10}
165: do_test subquery-2.2.1 {
166: execsql {
167: CREATE TABLE t3(a PRIMARY KEY, b);
168: INSERT INTO t3 VALUES(1, 2);
169: INSERT INTO t3 VALUES(3, 1);
170: }
171: } {}
172: do_test subquery-2.2.2 {
173: execsql {
174: SELECT * FROM t3 WHERE a IN (SELECT b FROM t3);
175: }
176: } {1 2}
177: do_test subquery-2.2.3 {
178: execsql {
179: DROP TABLE t3;
180: }
181: } {}
182: do_test subquery-2.3.1 {
183: execsql {
184: CREATE TABLE t3(a TEXT);
185: INSERT INTO t3 VALUES('10');
186: }
187: } {}
188: do_test subquery-2.3.2 {
189: execsql {
190: SELECT a IN (10.0, 20) FROM t3;
191: }
192: } {0}
193: do_test subquery-2.3.3 {
194: execsql {
195: DROP TABLE t3;
196: }
197: } {}
198: do_test subquery-2.4.1 {
199: execsql {
200: CREATE TABLE t3(a TEXT);
201: INSERT INTO t3 VALUES('XX');
202: }
203: } {}
204: do_test subquery-2.4.2 {
205: execsql {
206: SELECT count(*) FROM t3 WHERE a IN (SELECT 'XX')
207: }
208: } {1}
209: do_test subquery-2.4.3 {
210: execsql {
211: DROP TABLE t3;
212: }
213: } {}
214: do_test subquery-2.5.1 {
215: execsql {
216: CREATE TABLE t3(a INTEGER);
217: INSERT INTO t3 VALUES(10);
218:
219: CREATE TABLE t4(x TEXT);
220: INSERT INTO t4 VALUES('10.0');
221: }
222: } {}
223: do_test subquery-2.5.2 {
224: # In the expr "x IN (SELECT a FROM t3)" the RHS of the IN operator
225: # has text affinity and the LHS has integer affinity. The rule is
226: # that we try to convert both sides to an integer before doing the
227: # comparision. Hence, the integer value 10 in t3 will compare equal
228: # to the string value '10.0' in t4 because the t4 value will be
229: # converted into an integer.
230: execsql {
231: SELECT * FROM t4 WHERE x IN (SELECT a FROM t3);
232: }
233: } {10.0}
234: do_test subquery-2.5.3.1 {
235: # The t4i index cannot be used to resolve the "x IN (...)" constraint
236: # because the constraint has integer affinity but t4i has text affinity.
237: execsql {
238: CREATE INDEX t4i ON t4(x);
239: SELECT * FROM t4 WHERE x IN (SELECT a FROM t3);
240: }
241: } {10.0}
242: do_test subquery-2.5.3.2 {
243: # Verify that the t4i index was not used in the previous query
244: set ::sqlite_query_plan
245: } {t4 {}}
246: do_test subquery-2.5.4 {
247: execsql {
248: DROP TABLE t3;
249: DROP TABLE t4;
250: }
251: } {}
252:
253: #------------------------------------------------------------------
254: # The following test cases - subquery-3.* - test tickets that
255: # were raised during development of correlated subqueries.
256: #
257:
258: # Ticket 1083
259: ifcapable view {
260: do_test subquery-3.1 {
261: catchsql { DROP TABLE t1; }
262: catchsql { DROP TABLE t2; }
263: execsql {
264: CREATE TABLE t1(a,b);
265: INSERT INTO t1 VALUES(1,2);
266: CREATE VIEW v1 AS SELECT b FROM t1 WHERE a>0;
267: CREATE TABLE t2(p,q);
268: INSERT INTO t2 VALUES(2,9);
269: SELECT * FROM v1 WHERE EXISTS(SELECT * FROM t2 WHERE p=v1.b);
270: }
271: } {2}
272: do_test subquery-3.1.1 {
273: execsql {
274: SELECT * FROM v1 WHERE EXISTS(SELECT 1);
275: }
276: } {2}
277: } else {
278: catchsql { DROP TABLE t1; }
279: catchsql { DROP TABLE t2; }
280: execsql {
281: CREATE TABLE t1(a,b);
282: INSERT INTO t1 VALUES(1,2);
283: CREATE TABLE t2(p,q);
284: INSERT INTO t2 VALUES(2,9);
285: }
286: }
287:
288: # Ticket 1084
289: do_test subquery-3.2 {
290: catchsql {
291: CREATE TABLE t1(a,b);
292: INSERT INTO t1 VALUES(1,2);
293: }
294: execsql {
295: SELECT (SELECT t1.a) FROM t1;
296: }
297: } {1}
298:
299: # Test Cases subquery-3.3.* test correlated subqueries where the
300: # parent query is an aggregate query. Ticket #1105 is an example
301: # of such a query.
302: #
303: do_test subquery-3.3.1 {
304: execsql {
305: SELECT a, (SELECT b) FROM t1 GROUP BY a;
306: }
307: } {1 2}
308: do_test subquery-3.3.2 {
309: catchsql {DROP TABLE t2}
310: execsql {
311: CREATE TABLE t2(c, d);
312: INSERT INTO t2 VALUES(1, 'one');
313: INSERT INTO t2 VALUES(2, 'two');
314: SELECT a, (SELECT d FROM t2 WHERE a=c) FROM t1 GROUP BY a;
315: }
316: } {1 one}
317: do_test subquery-3.3.3 {
318: execsql {
319: INSERT INTO t1 VALUES(2, 4);
320: SELECT max(a), (SELECT d FROM t2 WHERE a=c) FROM t1;
321: }
322: } {2 two}
323: do_test subquery-3.3.4 {
324: execsql {
325: SELECT a, (SELECT (SELECT d FROM t2 WHERE a=c)) FROM t1 GROUP BY a;
326: }
327: } {1 one 2 two}
328: do_test subquery-3.3.5 {
329: execsql {
330: SELECT a, (SELECT count(*) FROM t2 WHERE a=c) FROM t1;
331: }
332: } {1 1 2 1}
333:
334: #------------------------------------------------------------------
335: # These tests - subquery-4.* - use the TCL statement cache to try
336: # and expose bugs to do with re-using statements that have been
337: # passed to sqlite3_reset().
338: #
339: # One problem was that VDBE memory cells were not being initialised
340: # to NULL on the second and subsequent executions.
341: #
342: do_test subquery-4.1.1 {
343: execsql {
344: SELECT (SELECT a FROM t1);
345: }
346: } {1}
347: do_test subquery-4.2 {
348: execsql {
349: DELETE FROM t1;
350: SELECT (SELECT a FROM t1);
351: }
352: } {{}}
353: do_test subquery-4.2.1 {
354: execsql {
355: CREATE TABLE t3(a PRIMARY KEY);
356: INSERT INTO t3 VALUES(10);
357: }
358: execsql {INSERT INTO t3 VALUES((SELECT max(a) FROM t3)+1)}
359: } {}
360: do_test subquery-4.2.2 {
361: execsql {INSERT INTO t3 VALUES((SELECT max(a) FROM t3)+1)}
362: } {}
363:
364: #------------------------------------------------------------------
365: # The subquery-5.* tests make sure string literals in double-quotes
366: # are handled efficiently. Double-quote literals are first checked
367: # to see if they match any column names. If there is not column name
368: # match then those literals are used a string constants. When a
369: # double-quoted string appears, we want to make sure that the search
370: # for a matching column name did not cause an otherwise static subquery
371: # to become a dynamic (correlated) subquery.
372: #
373: do_test subquery-5.1 {
374: proc callcntproc {n} {
375: incr ::callcnt
376: return $n
377: }
378: set callcnt 0
379: db function callcnt callcntproc
380: execsql {
381: CREATE TABLE t4(x,y);
382: INSERT INTO t4 VALUES('one',1);
383: INSERT INTO t4 VALUES('two',2);
384: INSERT INTO t4 VALUES('three',3);
385: INSERT INTO t4 VALUES('four',4);
386: CREATE TABLE t5(a,b);
387: INSERT INTO t5 VALUES(1,11);
388: INSERT INTO t5 VALUES(2,22);
389: INSERT INTO t5 VALUES(3,33);
390: INSERT INTO t5 VALUES(4,44);
391: SELECT b FROM t5 WHERE a IN
392: (SELECT callcnt(y)+0 FROM t4 WHERE x="two")
393: }
394: } {22}
395: do_test subquery-5.2 {
396: # This is the key test. The subquery should have only run once. If
397: # The double-quoted identifier "two" were causing the subquery to be
398: # processed as a correlated subquery, then it would have run 4 times.
399: set callcnt
400: } {1}
401:
402:
403: # Ticket #1380. Make sure correlated subqueries on an IN clause work
404: # correctly when the left-hand side of the IN operator is constant.
405: #
406: do_test subquery-6.1 {
407: set callcnt 0
408: execsql {
409: SELECT x FROM t4 WHERE 1 IN (SELECT callcnt(count(*)) FROM t5 WHERE a=y)
410: }
411: } {one two three four}
412: do_test subquery-6.2 {
413: set callcnt
414: } {4}
415: do_test subquery-6.3 {
416: set callcnt 0
417: execsql {
418: SELECT x FROM t4 WHERE 1 IN (SELECT callcnt(count(*)) FROM t5 WHERE a=1)
419: }
420: } {one two three four}
421: do_test subquery-6.4 {
422: set callcnt
423: } {1}
424:
425: if 0 { ############# disable until we get #2652 fixed
426: # Ticket #2652. Allow aggregate functions of outer queries inside
427: # a non-aggregate subquery.
428: #
429: do_test subquery-7.1 {
430: execsql {
431: CREATE TABLE t7(c7);
432: INSERT INTO t7 VALUES(1);
433: INSERT INTO t7 VALUES(2);
434: INSERT INTO t7 VALUES(3);
435: CREATE TABLE t8(c8);
436: INSERT INTO t8 VALUES(100);
437: INSERT INTO t8 VALUES(200);
438: INSERT INTO t8 VALUES(300);
439: CREATE TABLE t9(c9);
440: INSERT INTO t9 VALUES(10000);
441: INSERT INTO t9 VALUES(20000);
442: INSERT INTO t9 VALUES(30000);
443:
444: SELECT (SELECT c7+c8 FROM t7) FROM t8;
445: }
446: } {101 201 301}
447: do_test subquery-7.2 {
448: execsql {
449: SELECT (SELECT max(c7)+c8 FROM t7) FROM t8;
450: }
451: } {103 203 303}
452: do_test subquery-7.3 {
453: execsql {
454: SELECT (SELECT c7+max(c8) FROM t8) FROM t7
455: }
456: } {301}
457: do_test subquery-7.4 {
458: execsql {
459: SELECT (SELECT max(c7)+max(c8) FROM t8) FROM t7
460: }
461: } {303}
462: do_test subquery-7.5 {
463: execsql {
464: SELECT (SELECT c8 FROM t8 WHERE rowid=max(c7)) FROM t7
465: }
466: } {300}
467: do_test subquery-7.6 {
468: execsql {
469: SELECT (SELECT (SELECT max(c7+c8+c9) FROM t9) FROM t8) FROM t7
470: }
471: } {30101 30102 30103}
472: do_test subquery-7.7 {
473: execsql {
474: SELECT (SELECT (SELECT c7+max(c8+c9) FROM t9) FROM t8) FROM t7
475: }
476: } {30101 30102 30103}
477: do_test subquery-7.8 {
478: execsql {
479: SELECT (SELECT (SELECT max(c7)+c8+c9 FROM t9) FROM t8) FROM t7
480: }
481: } {10103}
482: do_test subquery-7.9 {
483: execsql {
484: SELECT (SELECT (SELECT c7+max(c8)+c9 FROM t9) FROM t8) FROM t7
485: }
486: } {10301 10302 10303}
487: do_test subquery-7.10 {
488: execsql {
489: SELECT (SELECT (SELECT c7+c8+max(c9) FROM t9) FROM t8) FROM t7
490: }
491: } {30101 30102 30103}
492: do_test subquery-7.11 {
493: execsql {
494: SELECT (SELECT (SELECT max(c7)+max(c8)+max(c9) FROM t9) FROM t8) FROM t7
495: }
496: } {30303}
497: } ;############# Disabled
498:
499: finish_test
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>