xref: /sqlite-3.40.0/test/like.test (revision 8a29dfde)
1# 2005 August 13
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 LIKE and GLOB operators and
13# in particular the optimizations that occur to help those operators
14# run faster.
15#
16# $Id: like.test,v 1.9 2008/02/23 21:55:40 drh Exp $
17
18set testdir [file dirname $argv0]
19source $testdir/tester.tcl
20
21# Create some sample data to work with.
22#
23do_test like-1.0 {
24  execsql {
25    CREATE TABLE t1(x TEXT);
26  }
27  foreach str {
28    a
29    ab
30    abc
31    abcd
32
33    acd
34    abd
35    bc
36    bcd
37
38    xyz
39    ABC
40    CDE
41    {ABC abc xyz}
42  } {
43    db eval {INSERT INTO t1 VALUES(:str)}
44  }
45  execsql {
46    SELECT count(*) FROM t1;
47  }
48} {12}
49
50# Test that both case sensitive and insensitive version of LIKE work.
51#
52do_test like-1.1 {
53  execsql {
54    SELECT x FROM t1 WHERE x LIKE 'abc' ORDER BY 1;
55  }
56} {ABC abc}
57do_test like-1.2 {
58  execsql {
59    SELECT x FROM t1 WHERE x GLOB 'abc' ORDER BY 1;
60  }
61} {abc}
62do_test like-1.3 {
63  execsql {
64    SELECT x FROM t1 WHERE x LIKE 'ABC' ORDER BY 1;
65  }
66} {ABC abc}
67do_test like-1.4 {
68  execsql {
69    SELECT x FROM t1 WHERE x LIKE 'aBc' ORDER BY 1;
70  }
71} {ABC abc}
72do_test like-1.5 {
73  execsql {
74    PRAGMA case_sensitive_like=on;
75    SELECT x FROM t1 WHERE x LIKE 'abc' ORDER BY 1;
76  }
77} {abc}
78do_test like-1.6 {
79  execsql {
80    SELECT x FROM t1 WHERE x GLOB 'abc' ORDER BY 1;
81  }
82} {abc}
83do_test like-1.7 {
84  execsql {
85    SELECT x FROM t1 WHERE x LIKE 'ABC' ORDER BY 1;
86  }
87} {ABC}
88do_test like-1.8 {
89  execsql {
90    SELECT x FROM t1 WHERE x LIKE 'aBc' ORDER BY 1;
91  }
92} {}
93do_test like-1.9 {
94  execsql {
95    PRAGMA case_sensitive_like=off;
96    SELECT x FROM t1 WHERE x LIKE 'abc' ORDER BY 1;
97  }
98} {ABC abc}
99
100# Tests of the REGEXP operator
101#
102do_test like-2.1 {
103  proc test_regexp {a b} {
104    return [regexp $a $b]
105  }
106  db function regexp test_regexp
107  execsql {
108    SELECT x FROM t1 WHERE x REGEXP 'abc' ORDER BY 1;
109  }
110} {{ABC abc xyz} abc abcd}
111do_test like-2.2 {
112  execsql {
113    SELECT x FROM t1 WHERE x REGEXP '^abc' ORDER BY 1;
114  }
115} {abc abcd}
116
117# Tests of the MATCH operator
118#
119do_test like-2.3 {
120  proc test_match {a b} {
121    return [string match $a $b]
122  }
123  db function match test_match
124  execsql {
125    SELECT x FROM t1 WHERE x MATCH '*abc*' ORDER BY 1;
126  }
127} {{ABC abc xyz} abc abcd}
128do_test like-2.4 {
129  execsql {
130    SELECT x FROM t1 WHERE x MATCH 'abc*' ORDER BY 1;
131  }
132} {abc abcd}
133
134# For the remaining tests, we need to have the like optimizations
135# enabled.
136#
137ifcapable !like_opt {
138  finish_test
139  return
140}
141
142# This procedure executes the SQL.  Then it appends to the result the
143# "sort" or "nosort" keyword (as in the cksort procedure above) then
144# it appends the ::sqlite_query_plan variable.
145#
146proc queryplan {sql} {
147  set ::sqlite_sort_count 0
148  set data [execsql $sql]
149  if {$::sqlite_sort_count} {set x sort} {set x nosort}
150  lappend data $x
151  return [concat $data $::sqlite_query_plan]
152}
153
154# Perform tests on the like optimization.
155#
156# With no index on t1.x and with case sensitivity turned off, no optimization
157# is performed.
158#
159do_test like-3.1 {
160  set sqlite_like_count 0
161  queryplan {
162    SELECT x FROM t1 WHERE x LIKE 'abc%' ORDER BY 1;
163  }
164} {ABC {ABC abc xyz} abc abcd sort t1 {}}
165do_test like-3.2 {
166  set sqlite_like_count
167} {12}
168
169# With an index on t1.x and case sensitivity on, optimize completely.
170#
171do_test like-3.3 {
172  set sqlite_like_count 0
173  execsql {
174    PRAGMA case_sensitive_like=on;
175    CREATE INDEX i1 ON t1(x);
176  }
177  queryplan {
178    SELECT x FROM t1 WHERE x LIKE 'abc%' ORDER BY 1;
179  }
180} {abc abcd nosort {} i1}
181do_test like-3.4 {
182  set sqlite_like_count
183} 0
184
185# Partial optimization when the pattern does not end in '%'
186#
187do_test like-3.5 {
188  set sqlite_like_count 0
189  queryplan {
190    SELECT x FROM t1 WHERE x LIKE 'a_c' ORDER BY 1;
191  }
192} {abc nosort {} i1}
193do_test like-3.6 {
194  set sqlite_like_count
195} 6
196do_test like-3.7 {
197  set sqlite_like_count 0
198  queryplan {
199    SELECT x FROM t1 WHERE x LIKE 'ab%d' ORDER BY 1;
200  }
201} {abcd abd nosort {} i1}
202do_test like-3.8 {
203  set sqlite_like_count
204} 4
205do_test like-3.9 {
206  set sqlite_like_count 0
207  queryplan {
208    SELECT x FROM t1 WHERE x LIKE 'a_c%' ORDER BY 1;
209  }
210} {abc abcd nosort {} i1}
211do_test like-3.10 {
212  set sqlite_like_count
213} 6
214
215# No optimization when the pattern begins with a wildcard.
216# Note that the index is still used but only for sorting.
217#
218do_test like-3.11 {
219  set sqlite_like_count 0
220  queryplan {
221    SELECT x FROM t1 WHERE x LIKE '%bcd' ORDER BY 1;
222  }
223} {abcd bcd nosort {} i1}
224do_test like-3.12 {
225  set sqlite_like_count
226} 12
227
228# No optimization for case insensitive LIKE
229#
230do_test like-3.13 {
231  set sqlite_like_count 0
232  queryplan {
233    PRAGMA case_sensitive_like=off;
234    SELECT x FROM t1 WHERE x LIKE 'abc%' ORDER BY 1;
235  }
236} {ABC {ABC abc xyz} abc abcd nosort {} i1}
237do_test like-3.14 {
238  set sqlite_like_count
239} 12
240
241# No optimization without an index.
242#
243do_test like-3.15 {
244  set sqlite_like_count 0
245  queryplan {
246    PRAGMA case_sensitive_like=on;
247    DROP INDEX i1;
248    SELECT x FROM t1 WHERE x LIKE 'abc%' ORDER BY 1;
249  }
250} {abc abcd sort t1 {}}
251do_test like-3.16 {
252  set sqlite_like_count
253} 12
254
255# No GLOB optimization without an index.
256#
257do_test like-3.17 {
258  set sqlite_like_count 0
259  queryplan {
260    SELECT x FROM t1 WHERE x GLOB 'abc*' ORDER BY 1;
261  }
262} {abc abcd sort t1 {}}
263do_test like-3.18 {
264  set sqlite_like_count
265} 12
266
267# GLOB is optimized regardless of the case_sensitive_like setting.
268#
269do_test like-3.19 {
270  set sqlite_like_count 0
271  queryplan {
272    CREATE INDEX i1 ON t1(x);
273    SELECT x FROM t1 WHERE x GLOB 'abc*' ORDER BY 1;
274  }
275} {abc abcd nosort {} i1}
276do_test like-3.20 {
277  set sqlite_like_count
278} 0
279do_test like-3.21 {
280  set sqlite_like_count 0
281  queryplan {
282    PRAGMA case_sensitive_like=on;
283    SELECT x FROM t1 WHERE x GLOB 'abc*' ORDER BY 1;
284  }
285} {abc abcd nosort {} i1}
286do_test like-3.22 {
287  set sqlite_like_count
288} 0
289do_test like-3.23 {
290  set sqlite_like_count 0
291  queryplan {
292    PRAGMA case_sensitive_like=off;
293    SELECT x FROM t1 WHERE x GLOB 'a[bc]d' ORDER BY 1;
294  }
295} {abd acd nosort {} i1}
296do_test like-3.24 {
297  set sqlite_like_count
298} 6
299
300# No optimization if the LHS of the LIKE is not a column name or
301# if the RHS is not a string.
302#
303do_test like-4.1 {
304  execsql {PRAGMA case_sensitive_like=on}
305  set sqlite_like_count 0
306  queryplan {
307    SELECT x FROM t1 WHERE x LIKE 'abc%' ORDER BY 1
308  }
309} {abc abcd nosort {} i1}
310do_test like-4.2 {
311  set sqlite_like_count
312} 0
313do_test like-4.3 {
314  set sqlite_like_count 0
315  queryplan {
316    SELECT x FROM t1 WHERE +x LIKE 'abc%' ORDER BY 1
317  }
318} {abc abcd nosort {} i1}
319do_test like-4.4 {
320  set sqlite_like_count
321} 12
322do_test like-4.5 {
323  set sqlite_like_count 0
324  queryplan {
325    SELECT x FROM t1 WHERE x LIKE ('ab' || 'c%') ORDER BY 1
326  }
327} {abc abcd nosort {} i1}
328do_test like-4.6 {
329  set sqlite_like_count
330} 12
331
332# Collating sequences on the index disable the LIKE optimization.
333# Or if the NOCASE collating sequence is used, the LIKE optimization
334# is enabled when case_sensitive_like is OFF.
335#
336do_test like-5.1 {
337  execsql {PRAGMA case_sensitive_like=off}
338  set sqlite_like_count 0
339  queryplan {
340    SELECT x FROM t1 WHERE x LIKE 'abc%' ORDER BY 1
341  }
342} {ABC {ABC abc xyz} abc abcd nosort {} i1}
343do_test like-5.2 {
344  set sqlite_like_count
345} 12
346do_test like-5.3 {
347  execsql {
348    CREATE TABLE t2(x COLLATE NOCASE);
349    INSERT INTO t2 SELECT * FROM t1;
350    CREATE INDEX i2 ON t2(x COLLATE NOCASE);
351  }
352  set sqlite_like_count 0
353  queryplan {
354    SELECT x FROM t2 WHERE x LIKE 'abc%' ORDER BY 1
355  }
356} {abc ABC {ABC abc xyz} abcd nosort {} i2}
357do_test like-5.4 {
358  set sqlite_like_count
359} 0
360do_test like-5.5 {
361  execsql {
362    PRAGMA case_sensitive_like=on;
363  }
364  set sqlite_like_count 0
365  queryplan {
366    SELECT x FROM t2 WHERE x LIKE 'abc%' ORDER BY 1
367  }
368} {abc abcd nosort {} i2}
369do_test like-5.6 {
370  set sqlite_like_count
371} 12
372do_test like-5.7 {
373  execsql {
374    PRAGMA case_sensitive_like=off;
375  }
376  set sqlite_like_count 0
377  queryplan {
378    SELECT x FROM t2 WHERE x GLOB 'abc*' ORDER BY 1
379  }
380} {abc abcd nosort {} i2}
381do_test like-5.8 {
382  set sqlite_like_count
383} 12
384do_test like-5.11 {
385  execsql {PRAGMA case_sensitive_like=off}
386  set sqlite_like_count 0
387  queryplan {
388    SELECT x FROM t1 WHERE x LIKE 'ABC%' ORDER BY 1
389  }
390} {ABC {ABC abc xyz} abc abcd nosort {} i1}
391do_test like-5.12 {
392  set sqlite_like_count
393} 12
394do_test like-5.13 {
395  set sqlite_like_count 0
396  queryplan {
397    SELECT x FROM t2 WHERE x LIKE 'ABC%' ORDER BY 1
398  }
399} {abc ABC {ABC abc xyz} abcd nosort {} i2}
400do_test like-5.14 {
401  set sqlite_like_count
402} 0
403do_test like-5.15 {
404  execsql {
405    PRAGMA case_sensitive_like=on;
406  }
407  set sqlite_like_count 0
408  queryplan {
409    SELECT x FROM t2 WHERE x LIKE 'ABC%' ORDER BY 1
410  }
411} {ABC {ABC abc xyz} nosort {} i2}
412do_test like-5.16 {
413  set sqlite_like_count
414} 12
415do_test like-5.17 {
416  execsql {
417    PRAGMA case_sensitive_like=off;
418  }
419  set sqlite_like_count 0
420  queryplan {
421    SELECT x FROM t2 WHERE x GLOB 'ABC*' ORDER BY 1
422  }
423} {ABC {ABC abc xyz} nosort {} i2}
424do_test like-5.18 {
425  set sqlite_like_count
426} 12
427
428# Boundary case.  The prefix for a LIKE comparison is rounded up
429# when constructing the comparison.  Example:  "ab" becomes "ac".
430# In other words, the last character is increased by one.
431#
432# Make sure this happens correctly when the last character is a
433# "z" and we are doing case-insensitive comparisons.
434#
435# Ticket #2959
436#
437do_test like-5.21 {
438  execsql {
439    PRAGMA case_sensitive_like=off;
440    INSERT INTO t2 VALUES('ZZ-upper-upper');
441    INSERT INTO t2 VALUES('zZ-lower-upper');
442    INSERT INTO t2 VALUES('Zz-upper-lower');
443    INSERT INTO t2 VALUES('zz-lower-lower');
444  }
445  queryplan {
446    SELECT x FROM t2 WHERE x LIKE 'zz%';
447  }
448} {zz-lower-lower zZ-lower-upper Zz-upper-lower ZZ-upper-upper nosort {} i2}
449do_test like-5.22 {
450  queryplan {
451    SELECT x FROM t2 WHERE x LIKE 'zZ%';
452  }
453} {zz-lower-lower zZ-lower-upper Zz-upper-lower ZZ-upper-upper nosort {} i2}
454do_test like-5.23 {
455  queryplan {
456    SELECT x FROM t2 WHERE x LIKE 'Zz%';
457  }
458} {zz-lower-lower zZ-lower-upper Zz-upper-lower ZZ-upper-upper nosort {} i2}
459do_test like-5.24 {
460  queryplan {
461    SELECT x FROM t2 WHERE x LIKE 'ZZ%';
462  }
463} {zz-lower-lower zZ-lower-upper Zz-upper-lower ZZ-upper-upper nosort {} i2}
464do_test like-5.25 {
465  queryplan {
466    PRAGMA case_sensitive_like=on;
467    CREATE TABLE t3(x);
468    CREATE INDEX i3 ON t3(x);
469    INSERT INTO t3 VALUES('ZZ-upper-upper');
470    INSERT INTO t3 VALUES('zZ-lower-upper');
471    INSERT INTO t3 VALUES('Zz-upper-lower');
472    INSERT INTO t3 VALUES('zz-lower-lower');
473    SELECT x FROM t3 WHERE x LIKE 'zz%';
474  }
475} {zz-lower-lower nosort {} i3}
476do_test like-5.26 {
477  queryplan {
478    SELECT x FROM t3 WHERE x LIKE 'zZ%';
479  }
480} {zZ-lower-upper nosort {} i3}
481do_test like-5.27 {
482  queryplan {
483    SELECT x FROM t3 WHERE x LIKE 'Zz%';
484  }
485} {Zz-upper-lower nosort {} i3}
486do_test like-5.28 {
487  queryplan {
488    SELECT x FROM t3 WHERE x LIKE 'ZZ%';
489  }
490} {ZZ-upper-upper nosort {} i3}
491
492
493# ticket #2407
494#
495# Make sure the LIKE prefix optimization does not strip off leading
496# characters of the like pattern that happen to be quote characters.
497#
498do_test like-6.1 {
499  foreach x { 'abc 'bcd 'def 'ax } {
500    set x2 '[string map {' ''} $x]'
501    db eval "INSERT INTO t2 VALUES($x2)"
502  }
503  execsql {
504    SELECT * FROM t2 WHERE x LIKE '''a%'
505  }
506} {'abc 'ax}
507
508do_test like-7.1 {
509  execsql {
510    SELECT * FROM t1 WHERE rowid GLOB '1*';
511  }
512} {a}
513
514finish_test
515