xref: /sqlite-3.40.0/test/indexexpr1.test (revision cb6acda9)
1# 2015-08-31
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 indexes on expressions.
13#
14
15set testdir [file dirname $argv0]
16source $testdir/tester.tcl
17
18do_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} {}
30do_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 |}
33do_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/}
37do_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 |}
40do_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/}
44
45do_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}
49do_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/}
53
54do_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 |}
57do_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}
61do_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/}
65do_execsql_test indexexpr1-142 {
66  SELECT rowid FROM t1 WHERE +substr(a,b,3)<='and' ORDER BY +rowid;
67} {1 2 3}
68do_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}
72do_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/}
77
78do_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}
85do_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/}
90
91# ORDER BY using an indexed expression
92#
93do_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}
97do_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/}
101do_execsql_test indexexpr1-171 {
102  SELECT length(a) FROM t1 ORDER BY length(a) DESC;
103} {52 38 29 27 25 20}
104do_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/}
108
109do_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} {}
121do_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 |}
124do_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/}
128do_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 |}
131do_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/}
135
136do_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}
140do_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/}
144
145do_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 |}
148do_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}
152do_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/}
156do_execsql_test indexexpr1-242 {
157  SELECT id FROM t1 WHERE +substr(a,b,3)<='and' ORDER BY +id;
158} {1 2 3}
159do_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}
163do_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/}
168
169do_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}
176do_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/}
181
182
183do_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}}
187do_catchsql_test indexexpr1-301 {
188  CREATE INDEX t2x1 ON t2(julianday('now',a));
189} {1 {non-deterministic function in index expression or CHECK constraint}}
190do_catchsql_test indexexpr1-310 {
191  CREATE INDEX t2x2 ON t2(a,b+(SELECT 15));
192} {1 {subqueries prohibited in index expressions}}
193do_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}}
196do_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}}
199do_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}}
202do_catchsql_test indexexpr1-340 {
203  CREATE TABLE e1(x,y,FOREIGN KEY(substr(y,1,5)) REFERENCES t1);
204} {1 {near "(": syntax error}}
205
206do_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}
215do_catchsql_test indexexpr1-410 {
216  INSERT INTO t3 SELECT * FROM t3 WHERE rowid=10;
217} {1 {UNIQUE constraint failed: index 't3abc'}}
218
219do_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} {}
228do_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}
234do_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/}
238
239# Skip-scan on an indexed expression
240#
241do_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}
253
254# Indexed expressions on both sides of an == in a WHERE clause.
255#
256do_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 |}
264do_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 |}
275
276# Collating sequences on indexes of expressions
277#
278do_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}
285do_catchsql_test indexexpr1-810 {
286  INSERT INTO t8(a,b) VALUES(4,'BARTHMERE');
287} {1 {UNIQUE constraint failed: index 't8bx'}}
288do_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 {}}
293
294# Check that PRAGMA integrity_check works correctly on a
295# UNIQUE index that includes rowid and expression terms.
296#
297do_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}
306do_catchsql_test indexexpr1-910 {
307  INSERT INTO t9(a,b,c,d) VALUES(5,6,7,-8);
308} {1 {UNIQUE constraint failed: index 't9x1'}}
309
310# Test cases derived from a NEVER() maro failure discovered by
311# Jonathan Metzman using AFL
312#
313do_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 |}
321do_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 |}
325
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
330#
331do_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}
342
343do_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);
351
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
355}
356do_execsql_test indexexpr1-1200.1 {
357  CREATE INDEX t10_ab ON t10(a+b);
358}
359do_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
363}
364do_execsql_test indexexpr1-1200.3 {
365  CREATE INDEX t10_abcd ON t10(a+b,c+d);
366}
367do_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
371}
372
373# Ticket https://www.sqlite.org/src/tktview/eb703ba7b50c1a
374# Incorrect result using an index on an expression with a collating function
375#
376do_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}
382
383# Ticket https://sqlite.org/src/tktview/aa98619a
384# Assertion fault using an index on a constant
385#
386do_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} {}
391do_execsql_test indexexpr1-1410 {
392  INSERT INTO t1400 VALUES('a'),('b');
393  SELECT 1 IN (SELECT 2) FROM t1400;
394} {0 0}
395do_execsql_test indexexpr1-1420 {
396  SELECT 1 IN (SELECT 2 UNION ALL SELECT 1) FROM t1400;
397} {1 1}
398do_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}
403
404
405finish_test
406