persistentstorage/sqlite3api/TEST/TclScript/like.test
changeset 0 08ec8eefde2f
equal deleted inserted replaced
-1:000000000000 0:08ec8eefde2f
       
     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.10 2008/09/09 12:31:34 drh Exp $
       
    17 
       
    18 set testdir [file dirname $argv0]
       
    19 source $testdir/tester.tcl
       
    20 
       
    21 # Create some sample data to work with.
       
    22 #
       
    23 do_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 #
       
    52 do_test like-1.1 {
       
    53   execsql {
       
    54     SELECT x FROM t1 WHERE x LIKE 'abc' ORDER BY 1;
       
    55   }
       
    56 } {ABC abc}
       
    57 do_test like-1.2 {
       
    58   execsql {
       
    59     SELECT x FROM t1 WHERE x GLOB 'abc' ORDER BY 1;
       
    60   }
       
    61 } {abc}
       
    62 do_test like-1.3 {
       
    63   execsql {
       
    64     SELECT x FROM t1 WHERE x LIKE 'ABC' ORDER BY 1;
       
    65   }
       
    66 } {ABC abc}
       
    67 do_test like-1.4 {
       
    68   execsql {
       
    69     SELECT x FROM t1 WHERE x LIKE 'aBc' ORDER BY 1;
       
    70   }
       
    71 } {ABC abc}
       
    72 do_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}
       
    78 do_test like-1.6 {
       
    79   execsql {
       
    80     SELECT x FROM t1 WHERE x GLOB 'abc' ORDER BY 1;
       
    81   }
       
    82 } {abc}
       
    83 do_test like-1.7 {
       
    84   execsql {
       
    85     SELECT x FROM t1 WHERE x LIKE 'ABC' ORDER BY 1;
       
    86   }
       
    87 } {ABC}
       
    88 do_test like-1.8 {
       
    89   execsql {
       
    90     SELECT x FROM t1 WHERE x LIKE 'aBc' ORDER BY 1;
       
    91   }
       
    92 } {}
       
    93 do_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 #
       
   102 do_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}
       
   111 do_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 #
       
   119 do_test like-2.3 {
       
   120   proc test_match {a b} {
       
   121     return [string match $a $b]
       
   122   }
       
   123   db function match -argcount 2 test_match
       
   124   execsql {
       
   125     SELECT x FROM t1 WHERE x MATCH '*abc*' ORDER BY 1;
       
   126   }
       
   127 } {{ABC abc xyz} abc abcd}
       
   128 do_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 #
       
   137 ifcapable !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 #
       
   146 proc 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 #
       
   159 do_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 {}}
       
   165 do_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 #
       
   171 do_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}
       
   181 do_test like-3.4 {
       
   182   set sqlite_like_count
       
   183 } 0
       
   184 
       
   185 # Partial optimization when the pattern does not end in '%'
       
   186 #
       
   187 do_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}
       
   193 do_test like-3.6 {
       
   194   set sqlite_like_count
       
   195 } 6
       
   196 do_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}
       
   202 do_test like-3.8 {
       
   203   set sqlite_like_count
       
   204 } 4
       
   205 do_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}
       
   211 do_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 #
       
   218 do_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}
       
   224 do_test like-3.12 {
       
   225   set sqlite_like_count
       
   226 } 12
       
   227 
       
   228 # No optimization for case insensitive LIKE
       
   229 #
       
   230 do_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}
       
   237 do_test like-3.14 {
       
   238   set sqlite_like_count
       
   239 } 12
       
   240 
       
   241 # No optimization without an index.
       
   242 #
       
   243 do_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 {}}
       
   251 do_test like-3.16 {
       
   252   set sqlite_like_count
       
   253 } 12
       
   254 
       
   255 # No GLOB optimization without an index.
       
   256 #
       
   257 do_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 {}}
       
   263 do_test like-3.18 {
       
   264   set sqlite_like_count
       
   265 } 12
       
   266 
       
   267 # GLOB is optimized regardless of the case_sensitive_like setting.
       
   268 #
       
   269 do_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}
       
   276 do_test like-3.20 {
       
   277   set sqlite_like_count
       
   278 } 0
       
   279 do_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}
       
   286 do_test like-3.22 {
       
   287   set sqlite_like_count
       
   288 } 0
       
   289 do_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}
       
   296 do_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 #
       
   303 do_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}
       
   310 do_test like-4.2 {
       
   311   set sqlite_like_count
       
   312 } 0
       
   313 do_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}
       
   319 do_test like-4.4 {
       
   320   set sqlite_like_count
       
   321 } 12
       
   322 do_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}
       
   328 do_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 #
       
   336 do_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}
       
   343 do_test like-5.2 {
       
   344   set sqlite_like_count
       
   345 } 12
       
   346 do_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}
       
   357 do_test like-5.4 {
       
   358   set sqlite_like_count
       
   359 } 0
       
   360 do_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}
       
   369 do_test like-5.6 {
       
   370   set sqlite_like_count
       
   371 } 12
       
   372 do_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}
       
   381 do_test like-5.8 {
       
   382   set sqlite_like_count
       
   383 } 12
       
   384 do_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}
       
   391 do_test like-5.12 {
       
   392   set sqlite_like_count
       
   393 } 12
       
   394 do_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}
       
   400 do_test like-5.14 {
       
   401   set sqlite_like_count
       
   402 } 0
       
   403 do_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}
       
   412 do_test like-5.16 {
       
   413   set sqlite_like_count
       
   414 } 12
       
   415 do_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}
       
   424 do_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 #
       
   437 do_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}
       
   449 do_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}
       
   454 do_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}
       
   459 do_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}
       
   464 do_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}
       
   476 do_test like-5.26 {
       
   477   queryplan {
       
   478     SELECT x FROM t3 WHERE x LIKE 'zZ%';
       
   479   }
       
   480 } {zZ-lower-upper nosort {} i3}
       
   481 do_test like-5.27 {
       
   482   queryplan {
       
   483     SELECT x FROM t3 WHERE x LIKE 'Zz%';
       
   484   }
       
   485 } {Zz-upper-lower nosort {} i3}
       
   486 do_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 #
       
   498 do_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 
       
   508 do_test like-7.1 {
       
   509   execsql {
       
   510     SELECT * FROM t1 WHERE rowid GLOB '1*';
       
   511   }
       
   512 } {a}
       
   513 
       
   514 # ticket #3345.
       
   515 #
       
   516 # Overloading the LIKE function with -1 for the number of arguments
       
   517 # will overload both the 2-argument and the 3-argument LIKE.
       
   518 #
       
   519 do_test like-8.1 {
       
   520   db eval {
       
   521     CREATE TABLE t8(x);
       
   522     INSERT INTO t8 VALUES('abcdef');
       
   523     INSERT INTO t8 VALUES('ghijkl');
       
   524     INSERT INTO t8 VALUES('mnopqr');
       
   525     SELECT 1, x FROM t8 WHERE x LIKE '%h%';
       
   526     SELECT 2, x FROM t8 WHERE x LIKE '%h%' ESCAPE 'x';
       
   527   }
       
   528 } {1 ghijkl 2 ghijkl}
       
   529 do_test like-8.2 {
       
   530   proc newlike {args} {return 1} ;# Alternative LIKE is always return TRUE
       
   531   db function like newlike       ;# Uses -1 for nArg in sqlite3_create_function
       
   532   db cache flush
       
   533   db eval {
       
   534     SELECT 1, x FROM t8 WHERE x LIKE '%h%';
       
   535     SELECT 2, x FROM t8 WHERE x LIKE '%h%' ESCAPE 'x';
       
   536   }
       
   537 } {1 ghijkl 2 ghijkl}
       
   538 do_test like-8.3 {
       
   539   db function like -argcount 2 newlike
       
   540   db eval {
       
   541     SELECT 1, x FROM t8 WHERE x LIKE '%h%';
       
   542     SELECT 2, x FROM t8 WHERE x LIKE '%h%' ESCAPE 'x';
       
   543   }
       
   544 } {1 abcdef 1 ghijkl 1 mnopqr 2 ghijkl}
       
   545 do_test like-8.4 {
       
   546   db function like -argcount 3 newlike
       
   547   db eval {
       
   548     SELECT 1, x FROM t8 WHERE x LIKE '%h%';
       
   549     SELECT 2, x FROM t8 WHERE x LIKE '%h%' ESCAPE 'x';
       
   550   }
       
   551 } {1 abcdef 1 ghijkl 1 mnopqr 2 abcdef 2 ghijkl 2 mnopqr}
       
   552 
       
   553 
       
   554 finish_test