Compute the correct column name even if the column identifier is the
[sqlite.git] / test / indexexpr1.test
blob28c23b9089afaf82ee9207a7752472abc074c5f3
1 # 2015-08-31
3 # The author disclaims copyright to this source code.  In place of
4 # a legal notice, here is a blessing:
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.
10 #***********************************************************************
11 # This file implements regression tests for SQLite library.  The
12 # focus of this file is testing indexes on expressions.
15 set testdir [file dirname $argv0]
16 source $testdir/tester.tcl
18 do_execsql_test indexexpr1-100 {
19   CREATE TABLE t1(a,b,c);
20   INSERT INTO t1(a,b,c)
21       /*  123456789 123456789 123456789 123456789 123456789 123456789 */ 
22   VALUES('In_the_beginning_was_the_Word',1,1),
23         ('and_the_Word_was_with_God',1,2),
24         ('and_the_Word_was_God',1,3),
25         ('The_same_was_in_the_beginning_with_God',2,1),
26         ('All_things_were_made_by_him',3,1),
27         ('and_without_him_was_not_any_thing_made_that_was_made',3,2);
28   CREATE INDEX t1a1 ON t1(substr(a,1,12));
29 } {}
30 do_execsql_test indexexpr1-110 {
31   SELECT b, c, '|' FROM t1 WHERE substr(a,1,12)=='and_the_Word' ORDER BY b, c;
32 } {1 2 | 1 3 |}
33 do_execsql_test indexexpr1-110eqp {
34   EXPLAIN QUERY PLAN
35   SELECT b, c, '|' FROM t1 WHERE substr(a,1,12)=='and_the_Word' ORDER BY b, c;
36 } {/USING INDEX t1a1/}
37 do_execsql_test indexexpr1-120 {
38   SELECT b, c, '|' FROM t1 WHERE 'and_the_Word'==substr(a,1,12) ORDER BY b, c;
39 } {1 2 | 1 3 |}
40 do_execsql_test indexexpr1-120eqp {
41   EXPLAIN QUERY PLAN
42   SELECT b, c, '|' FROM t1 WHERE 'and_the_Word'==substr(a,1,12) ORDER BY b, c;
43 } {/USING INDEX t1a1/}
45 do_execsql_test indexexpr1-130 {
46   CREATE INDEX t1ba ON t1(b,substr(a,2,3),c);
47   SELECT c FROM t1 WHERE b=1 AND substr(a,2,3)='nd_' ORDER BY c;
48 } {2 3}
49 do_execsql_test indexexpr1-130eqp {
50   EXPLAIN QUERY PLAN
51   SELECT c FROM t1 WHERE b=1 AND substr(a,2,3)='nd_' ORDER BY c;
52 } {/USING INDEX t1ba/}
54 do_execsql_test indexexpr1-140 {
55   SELECT rowid, substr(a,b,3), '|' FROM t1 ORDER BY 2;
56 } {1 In_ | 2 and | 3 and | 6 d_w | 4 he_ | 5 l_t |}
57 do_execsql_test indexexpr1-141 {
58   CREATE INDEX t1abx ON t1(substr(a,b,3));
59   SELECT rowid FROM t1 WHERE substr(a,b,3)<='and' ORDER BY +rowid;
60 } {1 2 3}
61 do_execsql_test indexexpr1-141eqp {
62   EXPLAIN QUERY PLAN
63   SELECT rowid FROM t1 WHERE substr(a,b,3)<='and' ORDER BY +rowid;
64 } {/USING INDEX t1abx/}
65 do_execsql_test indexexpr1-142 {
66   SELECT rowid FROM t1 WHERE +substr(a,b,3)<='and' ORDER BY +rowid;
67 } {1 2 3}
68 do_execsql_test indexexpr1-150 {
69   SELECT rowid FROM t1 WHERE substr(a,b,3) IN ('and','l_t','xyz')
70    ORDER BY +rowid;
71 } {2 3 5}
72 do_execsql_test indexexpr1-150eqp {
73   EXPLAIN QUERY PLAN
74   SELECT rowid FROM t1 WHERE substr(a,b,3) IN ('and','l_t','xyz')
75    ORDER BY +rowid;
76 } {/USING INDEX t1abx/}
78 do_execsql_test indexexpr1-160 {
79   ALTER TABLE t1 ADD COLUMN d;
80   UPDATE t1 SET d=length(a);
81   CREATE INDEX t1a2 ON t1(SUBSTR(a, 27, 3)) WHERE d>=29;
82   SELECT rowid, b, c FROM t1
83    WHERE substr(a,27,3)=='ord' AND d>=29;
84 } {1 1 1}
85 do_execsql_test indexexpr1-160eqp {
86   EXPLAIN QUERY PLAN
87   SELECT rowid, b, c FROM t1
88    WHERE substr(a,27,3)=='ord' AND d>=29;
89 } {/USING INDEX t1a2/}
91 # ORDER BY using an indexed expression
93 do_execsql_test indexexpr1-170 {
94   CREATE INDEX t1alen ON t1(length(a));
95   SELECT length(a) FROM t1 ORDER BY length(a);
96 } {20 25 27 29 38 52}
97 do_execsql_test indexexpr1-170eqp {
98   EXPLAIN QUERY PLAN
99   SELECT length(a) FROM t1 ORDER BY length(a);
100 } {/SCAN TABLE t1 USING INDEX t1alen/}
101 do_execsql_test indexexpr1-171 {
102   SELECT length(a) FROM t1 ORDER BY length(a) DESC;
103 } {52 38 29 27 25 20}
104 do_execsql_test indexexpr1-171eqp {
105   EXPLAIN QUERY PLAN
106   SELECT length(a) FROM t1 ORDER BY length(a) DESC;
107 } {/SCAN TABLE t1 USING INDEX t1alen/}
109 do_execsql_test indexexpr1-200 {
110   DROP TABLE t1;
111   CREATE TABLE t1(id ANY PRIMARY KEY, a,b,c) WITHOUT ROWID;
112   INSERT INTO t1(id,a,b,c)
113   VALUES(1,'In_the_beginning_was_the_Word',1,1),
114         (2,'and_the_Word_was_with_God',1,2),
115         (3,'and_the_Word_was_God',1,3),
116         (4,'The_same_was_in_the_beginning_with_God',2,1),
117         (5,'All_things_were_made_by_him',3,1),
118         (6,'and_without_him_was_not_any_thing_made_that_was_made',3,2);
119   CREATE INDEX t1a1 ON t1(substr(a,1,12));
120 } {}
121 do_execsql_test indexexpr1-210 {
122   SELECT b, c, '|' FROM t1 WHERE substr(a,1,12)=='and_the_Word' ORDER BY b, c;
123 } {1 2 | 1 3 |}
124 do_execsql_test indexexpr1-210eqp {
125   EXPLAIN QUERY PLAN
126   SELECT b, c, '|' FROM t1 WHERE substr(a,1,12)=='and_the_Word' ORDER BY b, c;
127 } {/USING INDEX t1a1/}
128 do_execsql_test indexexpr1-220 {
129   SELECT b, c, '|' FROM t1 WHERE 'and_the_Word'==substr(a,1,12) ORDER BY b, c;
130 } {1 2 | 1 3 |}
131 do_execsql_test indexexpr1-220eqp {
132   EXPLAIN QUERY PLAN
133   SELECT b, c, '|' FROM t1 WHERE 'and_the_Word'==substr(a,1,12) ORDER BY b, c;
134 } {/USING INDEX t1a1/}
136 do_execsql_test indexexpr1-230 {
137   CREATE INDEX t1ba ON t1(b,substr(a,2,3),c);
138   SELECT c FROM t1 WHERE b=1 AND substr(a,2,3)='nd_' ORDER BY c;
139 } {2 3}
140 do_execsql_test indexexpr1-230eqp {
141   EXPLAIN QUERY PLAN
142   SELECT c FROM t1 WHERE b=1 AND substr(a,2,3)='nd_' ORDER BY c;
143 } {/USING INDEX t1ba/}
145 do_execsql_test indexexpr1-240 {
146   SELECT id, substr(a,b,3), '|' FROM t1 ORDER BY 2;
147 } {1 In_ | 2 and | 3 and | 6 d_w | 4 he_ | 5 l_t |}
148 do_execsql_test indexexpr1-241 {
149   CREATE INDEX t1abx ON t1(substr(a,b,3));
150   SELECT id FROM t1 WHERE substr(a,b,3)<='and' ORDER BY +id;
151 } {1 2 3}
152 do_execsql_test indexexpr1-241eqp {
153   EXPLAIN QUERY PLAN
154   SELECT id FROM t1 WHERE substr(a,b,3)<='and' ORDER BY +id;
155 } {/USING INDEX t1abx/}
156 do_execsql_test indexexpr1-242 {
157   SELECT id FROM t1 WHERE +substr(a,b,3)<='and' ORDER BY +id;
158 } {1 2 3}
159 do_execsql_test indexexpr1-250 {
160   SELECT id FROM t1 WHERE substr(a,b,3) IN ('and','l_t','xyz')
161    ORDER BY +id;
162 } {2 3 5}
163 do_execsql_test indexexpr1-250eqp {
164   EXPLAIN QUERY PLAN
165   SELECT id FROM t1 WHERE substr(a,b,3) IN ('and','l_t','xyz')
166    ORDER BY +id;
167 } {/USING INDEX t1abx/}
169 do_execsql_test indexexpr1-260 {
170   ALTER TABLE t1 ADD COLUMN d;
171   UPDATE t1 SET d=length(a);
172   CREATE INDEX t1a2 ON t1(SUBSTR(a, 27, 3)) WHERE d>=29;
173   SELECT id, b, c FROM t1
174    WHERE substr(a,27,3)=='ord' AND d>=29;
175 } {1 1 1}
176 do_execsql_test indexexpr1-260eqp {
177   EXPLAIN QUERY PLAN
178   SELECT id, b, c FROM t1
179    WHERE substr(a,27,3)=='ord' AND d>=29;
180 } {/USING INDEX t1a2/}
183 do_catchsql_test indexexpr1-300 {
184   CREATE TABLE t2(a,b,c); INSERT INTO t2 VALUES(1,2,3);
185   CREATE INDEX t2x1 ON t2(a,b+random());
186 } {1 {non-deterministic functions prohibited in index expressions}}
187 do_catchsql_test indexexpr1-301 {
188   CREATE INDEX t2x1 ON t2(julianday('now',a));
189 } {1 {non-deterministic function in index expression or CHECK constraint}}
190 do_catchsql_test indexexpr1-310 {
191   CREATE INDEX t2x2 ON t2(a,b+(SELECT 15));
192 } {1 {subqueries prohibited in index expressions}}
193 do_catchsql_test indexexpr1-320 {
194   CREATE TABLE e1(x,y,UNIQUE(y,substr(x,1,5)));
195 } {1 {expressions prohibited in PRIMARY KEY and UNIQUE constraints}}
196 do_catchsql_test indexexpr1-330 {
197   CREATE TABLE e1(x,y,PRIMARY KEY(y,substr(x,1,5)));
198 } {1 {expressions prohibited in PRIMARY KEY and UNIQUE constraints}}
199 do_catchsql_test indexexpr1-331 {
200   CREATE TABLE e1(x,y,PRIMARY KEY(y,substr(x,1,5))) WITHOUT ROWID;
201 } {1 {expressions prohibited in PRIMARY KEY and UNIQUE constraints}}
202 do_catchsql_test indexexpr1-340 {
203   CREATE TABLE e1(x,y,FOREIGN KEY(substr(y,1,5)) REFERENCES t1);
204 } {1 {near "(": syntax error}}
206 do_execsql_test indexexpr1-400 {
207   CREATE TABLE t3(a,b,c);
208   WITH RECURSIVE c(x) AS (VALUES(1) UNION SELECT x+1 FROM c WHERE x<30)
209   INSERT INTO t3(a,b,c)
210     SELECT x, printf('ab%04xyz',x), random() FROM c;
211   CREATE UNIQUE INDEX t3abc ON t3(CAST(a AS text), b, substr(c,1,3));
212   SELECT a FROM t3 WHERE CAST(a AS text)<='10' ORDER BY +a;
213   PRAGMA integrity_check;
214 } {1 10 ok}
215 do_catchsql_test indexexpr1-410 {
216   INSERT INTO t3 SELECT * FROM t3 WHERE rowid=10;
217 } {1 {UNIQUE constraint failed: index 't3abc'}}
219 do_execsql_test indexexpr1-500 {
220   CREATE TABLE t5(a);
221   CREATE TABLE cnt(x);
222   WITH RECURSIVE
223     c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<5)
224   INSERT INTO cnt(x) SELECT x FROM c;
225   INSERT INTO t5(a) SELECT printf('abc%03dxyz',x) FROM cnt;
226   CREATE INDEX t5ax ON t5( substr(a,4,3) );
227 } {}
228 do_execsql_test indexexpr1-510 {
229   -- The use of the "k" alias in the WHERE clause is technically
230   -- illegal, but SQLite allows it for historical reasons.  In this
231   -- test and the next, verify that "k" can be used by the t5ax index
232   SELECT substr(a,4,3) AS k FROM cnt, t5 WHERE k=printf('%03d',x);
233 } {001 002 003 004 005}
234 do_execsql_test indexexpr1-510eqp {
235   EXPLAIN QUERY PLAN
236   SELECT substr(a,4,3) AS k FROM cnt, t5 WHERE k=printf('%03d',x);
237 } {/USING INDEX t5ax/}
239 # Skip-scan on an indexed expression
241 do_execsql_test indexexpr1-600 {
242   DROP TABLE IF EXISTS t4;
243   CREATE TABLE t4(a,b,c,d,e,f,g,h,i);
244   CREATE INDEX t4all ON t4(a,b,c<d,e,f,i,h);
245   INSERT INTO t4 VALUES(1,2,3,4,5,6,7,8,9);
246   ANALYZE;
247   DELETE FROM sqlite_stat1;
248   INSERT INTO sqlite_stat1
249     VALUES('t4','t4all','600000 160000 40000 10000 2000 600 100 40 10');
250   ANALYZE sqlite_master;
251   SELECT i FROM t4 WHERE e=5;
252 } {9}
254 # Indexed expressions on both sides of an == in a WHERE clause.
256 do_execsql_test indexexpr1-700 {
257   DROP TABLE IF EXISTS t7;
258   CREATE TABLE t7(a,b,c);
259   INSERT INTO t7(a,b,c) VALUES(1,2,2),('abc','def','def'),(4,5,6);
260   CREATE INDEX t7b ON t7(+b);
261   CREATE INDEX t7c ON t7(+c);
262   SELECT *, '|' FROM t7 WHERE +b=+c ORDER BY +a;
263 } {1 2 2 | abc def def |}
264 do_execsql_test indexexpr1-710 {
265   CREATE TABLE t71(a,b,c);
266   CREATE INDEX t71bc ON t71(b+c);
267   CREATE TABLE t72(x,y,z);
268   CREATE INDEX t72yz ON t72(y+z);
269   INSERT INTO t71(a,b,c) VALUES(1,11,2),(2,7,15),(3,5,4);
270   INSERT INTO t72(x,y,z) VALUES(1,10,3),(2,8,14),(3,9,9);
271   SELECT a, x, '|' FROM t71, t72
272    WHERE b+c=y+z
273   ORDER BY +a, +x;
274 } {1 1 | 2 2 |}
276 # Collating sequences on indexes of expressions
278 do_execsql_test indexexpr1-800 {
279   DROP TABLE IF EXISTS t8;
280   CREATE TABLE t8(a INTEGER PRIMARY KEY, b TEXT);
281   CREATE UNIQUE INDEX t8bx ON t8(substr(b,2,4) COLLATE nocase);
282   INSERT INTO t8(a,b) VALUES(1,'Alice'),(2,'Bartholemew'),(3,'Cynthia');
283   SELECT * FROM t8 WHERE substr(b,2,4)='ARTH' COLLATE nocase;
284 } {2 Bartholemew}
285 do_catchsql_test indexexpr1-810 {
286   INSERT INTO t8(a,b) VALUES(4,'BARTHMERE');
287 } {1 {UNIQUE constraint failed: index 't8bx'}}
288 do_catchsql_test indexexpr1-820 {
289   DROP INDEX t8bx;
290   CREATE UNIQUE INDEX t8bx ON t8(substr(b,2,4) COLLATE rtrim);
291   INSERT INTO t8(a,b) VALUES(4,'BARTHMERE');
292 } {0 {}}
294 # Check that PRAGMA integrity_check works correctly on a
295 # UNIQUE index that includes rowid and expression terms.
297 do_execsql_test indexexpr1-900 {
298   CREATE TABLE t9(a,b,c,d);
299   CREATE UNIQUE INDEX t9x1 ON t9(c,abs(d),b);
300   INSERT INTO t9(rowid,a,b,c,d) VALUES(1,2,3,4,5);
301   INSERT INTO t9(rowid,a,b,c,d) VALUES(2,NULL,NULL,NULL,NULL);
302   INSERT INTO t9(rowid,a,b,c,d) VALUES(3,NULL,NULL,NULL,NULL);
303   INSERT INTO t9(rowid,a,b,c,d) VALUES(4,5,6,7,8);
304   PRAGMA integrity_check;
305 } {ok}
306 do_catchsql_test indexexpr1-910 {
307   INSERT INTO t9(a,b,c,d) VALUES(5,6,7,-8);
308 } {1 {UNIQUE constraint failed: index 't9x1'}}
310 # Test cases derived from a NEVER() maro failure discovered by
311 # Jonathan Metzman using AFL
313 do_execsql_test indexexpr1-1000 {
314   DROP TABLE IF EXISTS t0;
315   CREATE TABLE t0(a,b,t);
316   CREATE INDEX i ON t0(a in(0,1));
317   INSERT INTO t0 VALUES(0,1,2),(2,3,4),(5,6,7);
318   UPDATE t0 SET b=99 WHERE (a in(0,1))=0;
319   SELECT *, '|' FROM t0 ORDER BY +a;
320 } {0 1 2 | 2 99 4 | 5 99 7 |}
321 do_execsql_test indexexpr1-1010 {
322   UPDATE t0 SET b=88 WHERE (a in(0,1))=1;
323   SELECT *, '|' FROM t0 ORDER BY +a;
324 } {0 88 2 | 2 99 4 | 5 99 7 |}
326 # 2016-10-10
327 # Make sure indexes on expressions skip over initial NULL values in the
328 # index as they are suppose to do.
329 # Ticket https://www.sqlite.org/src/tktview/4baa46491212947
331 do_execsql_test indexexpr1-1100 {
332   DROP TABLE IF EXISTS t1;
333   CREATE TABLE t1(a);
334   INSERT INTO t1 VALUES(NULL),(1);
335   SELECT '1:', typeof(a), a FROM t1 WHERE a<10;
336   SELECT '2:', typeof(a), a FROM t1 WHERE a+0<10;
337   CREATE INDEX t1x1 ON t1(a);
338   CREATE INDEX t1x2 ON t1(a+0);
339   SELECT '3:', typeof(a), a FROM t1 WHERE a<10;
340   SELECT '4:', typeof(a), a FROM t1 WHERE a+0<10;
341 } {1: integer 1 2: integer 1 3: integer 1 4: integer 1}
343 do_execsql_test indexexpr1-1200 {
344   CREATE TABLE t10(a int, b int, c int, d int);
345   INSERT INTO t10(a, b, c, d) VALUES(0, 0, 2, 2);
346   INSERT INTO t10(a, b, c, d) VALUES(0, 0, 0, 0);
347   INSERT INTO t10(a, b, c, d) VALUES(0, 0, 1, 1);
348   INSERT INTO t10(a, b, c, d) VALUES(1, 1, 1, 1);
349   INSERT INTO t10(a, b, c, d) VALUES(1, 1, 0, 0);
350   INSERT INTO t10(a, b, c, d) VALUES(2, 2, 0, 0);
352   SELECT a+b, c+d FROM t10 ORDER BY a+b, c+d;
353 } {
354   0 0 0 2 0 4 2 0 2 2 4 0
356 do_execsql_test indexexpr1-1200.1 {
357   CREATE INDEX t10_ab ON t10(a+b);
359 do_execsql_test indexexpr1-1200.2 {
360   SELECT a+b, c+d FROM t10 ORDER BY a+b, c+d;
361 } {
362   0 0 0 2 0 4 2 0 2 2 4 0
364 do_execsql_test indexexpr1-1200.3 {
365   CREATE INDEX t10_abcd ON t10(a+b,c+d);
367 do_execsql_test indexexpr1-1200.4 {
368   SELECT a+b, c+d FROM t10 ORDER BY a+b, c+d;
369 } {
370   0 0 0 2 0 4 2 0 2 2 4 0
373 # Ticket https://www.sqlite.org/src/tktview/eb703ba7b50c1a
374 # Incorrect result using an index on an expression with a collating function
376 do_execsql_test indexexpr1-1300.1 {
377   CREATE TABLE t1300(a INTEGER PRIMARY KEY, b);
378   INSERT INTO t1300 VALUES(1,'coffee'),(2,'COFFEE'),(3,'stress'),(4,'STRESS');
379   CREATE INDEX t1300bexpr ON t1300( substr(b,4) );
380   SELECT a FROM t1300 WHERE substr(b,4)='ess' COLLATE nocase ORDER BY +a;
381 } {3 4}
383 # Ticket https://sqlite.org/src/tktview/aa98619a
384 # Assertion fault using an index on a constant
386 do_execsql_test indexexpr1-1400 {
387   CREATE TABLE t1400(x TEXT);
388   CREATE INDEX t1400x ON t1400(1);  -- Index on a constant
389   SELECT 1 IN (SELECT 2) FROM t1400;
390 } {}
391 do_execsql_test indexexpr1-1410 {
392   INSERT INTO t1400 VALUES('a'),('b');
393   SELECT 1 IN (SELECT 2) FROM t1400;
394 } {0 0}
395 do_execsql_test indexexpr1-1420 {
396   SELECT 1 IN (SELECT 2 UNION ALL SELECT 1) FROM t1400;
397 } {1 1}
398 do_execsql_test indexexpr1-1430 {
399   DROP INDEX t1400x;
400   CREATE INDEX t1400x ON t1400(abs(15+3));
401   SELECT abs(15+3) IN (SELECT 17 UNION ALL SELECT 18) FROM t1;
402 } {1 1}
404 # 2018-01-02 ticket https://sqlite.org/src/info/dc3f932f5a147771
405 # A REPLACE into a table that uses an index on an expression causes
406 # an assertion fault.  Problem discovered by OSSFuzz.
408 do_execsql_test indexexpr1-1500 {
409   CREATE TABLE t1500(a INT PRIMARY KEY, b INT UNIQUE);
410   CREATE INDEX t1500ab ON t1500(a*b);
411   INSERT INTO t1500(a,b) VALUES(1,2);
412   REPLACE INTO t1500(a,b) VALUES(1,3);  -- formerly caused assertion fault
413   SELECT * FROM t1500;
414 } {1 3}
416 # 2018-01-03 OSSFuzz discovers another test case for the same problem
417 # above.
419 do_execsql_test indexexpr-1510 {
420   DROP TABLE IF EXISTS t1;
421   CREATE TABLE t1(a PRIMARY KEY,b UNIQUE);
422   REPLACE INTO t1 VALUES(2, 1);
423   REPLACE INTO t1 SELECT 6,1;
424   CREATE INDEX t1aa ON t1(a-a);
425   REPLACE INTO t1 SELECT a, randomblob(a) FROM t1
426 } {}
428 finish_test