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.6 2007/06/11 12:56:15 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 384 385# ticket #2407 386# 387# Make sure the LIKE prefix optimization does not strip off leading 388# characters of the like pattern that happen to be quote characters. 389# 390do_test like-6.1 { 391 foreach x { 'abc 'bcd 'def 'ax } { 392 db eval {INSERT INTO t2 VALUES($x)} 393 } 394 execsql { 395 SELECT * FROM t2 WHERE x LIKE '''a%' 396 } 397} {'abc 'ax} 398 399finish_test 400