1# 2001 September 15 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 script is page cache subsystem. 13# 14# $Id: collate3.test,v 1.10 2005/01/29 08:32:46 danielk1977 Exp $ 15 16set testdir [file dirname $argv0] 17source $testdir/tester.tcl 18 19# 20# Tests are organised as follows: 21# 22# collate3.1.* - Errors related to unknown collation sequences. 23# collate3.2.* - Errors related to undefined collation sequences. 24# collate3.3.* - Writing to a table that has an index with an undefined c.s. 25# collate3.4.* - Misc errors. 26# collate3.5.* - Collation factory. 27# 28 29# 30# These tests ensure that when a user executes a statement with an 31# unknown collation sequence an error is returned. 32# 33do_test collate3-1.0 { 34 execsql { 35 CREATE TABLE collate3t1(c1); 36 } 37} {} 38do_test collate3-1.1 { 39 catchsql { 40 SELECT * FROM collate3t1 ORDER BY 1 collate garbage; 41 } 42} {1 {no such collation sequence: garbage}} 43do_test collate3-1.2 { 44 catchsql { 45 CREATE TABLE collate3t2(c1 collate garbage); 46 } 47} {1 {no such collation sequence: garbage}} 48do_test collate3-1.3 { 49 catchsql { 50 CREATE INDEX collate3i1 ON collate3t1(c1 COLLATE garbage); 51 } 52} {1 {no such collation sequence: garbage}} 53 54execsql { 55 DROP TABLE collate3t1; 56} 57 58# 59# Create a table with a default collation sequence, then close 60# and re-open the database without re-registering the collation 61# sequence. Then make sure the library stops us from using 62# the collation sequence in: 63# * an explicitly collated ORDER BY 64# * an ORDER BY that uses the default collation sequence 65# * an expression (=) 66# * a CREATE TABLE statement 67# * a CREATE INDEX statement that uses a default collation sequence 68# * a GROUP BY that uses the default collation sequence 69# * a SELECT DISTINCT that uses the default collation sequence 70# * Compound SELECTs that uses the default collation sequence 71# * An ORDER BY on a compound SELECT with an explicit ORDER BY. 72# 73do_test collate3-2.0 { 74 db collate string_compare {string compare} 75 execsql { 76 CREATE TABLE collate3t1(c1 COLLATE string_compare, c2); 77 } 78 db close 79 sqlite3 db test.db 80 expr 0 81} 0 82do_test collate3-2.1 { 83 catchsql { 84 SELECT * FROM collate3t1 ORDER BY 1 COLLATE string_compare; 85 } 86} {1 {no such collation sequence: string_compare}} 87do_test collate3-2.2 { 88 catchsql { 89 SELECT * FROM collate3t1 ORDER BY c1; 90 } 91} {1 {no such collation sequence: string_compare}} 92do_test collate3-2.3 { 93 catchsql { 94 SELECT * FROM collate3t1 WHERE c1 = 'xxx'; 95 } 96} {1 {no such collation sequence: string_compare}} 97do_test collate3-2.4 { 98 catchsql { 99 CREATE TABLE collate3t2(c1 COLLATE string_compare); 100 } 101} {1 {no such collation sequence: string_compare}} 102do_test collate3-2.5 { 103 catchsql { 104 CREATE INDEX collate3t1_i1 ON collate3t1(c1); 105 } 106} {1 {no such collation sequence: string_compare}} 107do_test collate3-2.6 { 108 catchsql { 109 SELECT * FROM collate3t1; 110 } 111} {0 {}} 112do_test collate3-2.7.1 { 113 catchsql { 114 SELECT count(*) FROM collate3t1 GROUP BY c1; 115 } 116} {1 {no such collation sequence: string_compare}} 117# do_test collate3-2.7.2 { 118# catchsql { 119# SELECT * FROM collate3t1 GROUP BY c1; 120# } 121# } {1 {GROUP BY may only be used on aggregate queries}} 122do_test collate3-2.7.2 { 123 catchsql { 124 SELECT * FROM collate3t1 GROUP BY c1; 125 } 126} {1 {no such collation sequence: string_compare}} 127do_test collate3-2.8 { 128 catchsql { 129 SELECT DISTINCT c1 FROM collate3t1; 130 } 131} {1 {no such collation sequence: string_compare}} 132 133ifcapable compound { 134 do_test collate3-2.9 { 135 catchsql { 136 SELECT c1 FROM collate3t1 UNION SELECT c1 FROM collate3t1; 137 } 138 } {1 {no such collation sequence: string_compare}} 139 do_test collate3-2.10 { 140 catchsql { 141 SELECT c1 FROM collate3t1 EXCEPT SELECT c1 FROM collate3t1; 142 } 143 } {1 {no such collation sequence: string_compare}} 144 do_test collate3-2.11 { 145 catchsql { 146 SELECT c1 FROM collate3t1 INTERSECT SELECT c1 FROM collate3t1; 147 } 148 } {1 {no such collation sequence: string_compare}} 149 do_test collate3-2.12 { 150 catchsql { 151 SELECT c1 FROM collate3t1 UNION ALL SELECT c1 FROM collate3t1; 152 } 153 } {0 {}} 154 do_test collate3-2.13 { 155 catchsql { 156 SELECT 10 UNION ALL SELECT 20 ORDER BY 1 COLLATE string_compare; 157 } 158 } {1 {no such collation sequence: string_compare}} 159 do_test collate3-2.14 { 160 catchsql { 161 SELECT 10 INTERSECT SELECT 20 ORDER BY 1 COLLATE string_compare; 162 } 163 } {1 {no such collation sequence: string_compare}} 164 do_test collate3-2.15 { 165 catchsql { 166 SELECT 10 EXCEPT SELECT 20 ORDER BY 1 COLLATE string_compare; 167 } 168 } {1 {no such collation sequence: string_compare}} 169 do_test collate3-2.16 { 170 catchsql { 171 SELECT 10 UNION SELECT 20 ORDER BY 1 COLLATE string_compare; 172 } 173 } {1 {no such collation sequence: string_compare}} 174 do_test collate3-2.17 { 175 catchsql { 176 SELECT c1 FROM collate3t1 UNION ALL SELECT c1 FROM collate3t1 ORDER BY 1; 177 } 178 } {1 {no such collation sequence: string_compare}} 179} ;# ifcapable compound 180 181# 182# Create an index that uses a collation sequence then close and 183# re-open the database without re-registering the collation 184# sequence. Then check that for the table with the index 185# * An INSERT fails, 186# * An UPDATE on the column with the index fails, 187# * An UPDATE on a different column succeeds. 188# * A DELETE with a WHERE clause fails 189# * A DELETE without a WHERE clause succeeds 190# 191# Also, ensure that the restrictions tested by collate3-2.* still 192# apply after the index has been created. 193# 194do_test collate3-3.0 { 195 db collate string_compare {string compare} 196 execsql { 197 CREATE INDEX collate3t1_i1 ON collate3t1(c1); 198 INSERT INTO collate3t1 VALUES('xxx', 'yyy'); 199 } 200 db close 201 sqlite3 db test.db 202 expr 0 203} 0 204db eval {select * from collate3t1} 205do_test collate3-3.1 { 206 catchsql { 207 INSERT INTO collate3t1 VALUES('xxx', 0); 208 } 209} {1 {no such collation sequence: string_compare}} 210do_test collate3-3.2 { 211 catchsql { 212 UPDATE collate3t1 SET c1 = 'xxx'; 213 } 214} {1 {no such collation sequence: string_compare}} 215do_test collate3-3.3 { 216 catchsql { 217 UPDATE collate3t1 SET c2 = 'xxx'; 218 } 219} {0 {}} 220do_test collate3-3.4 { 221 catchsql { 222 DELETE FROM collate3t1 WHERE 1; 223 } 224} {1 {no such collation sequence: string_compare}} 225do_test collate3-3.5 { 226 catchsql { 227 SELECT * FROM collate3t1; 228 } 229} {0 {xxx xxx}} 230do_test collate3-3.6 { 231 catchsql { 232 DELETE FROM collate3t1; 233 } 234} {0 {}} 235ifcapable {integrityck} { 236 do_test collate3-3.8 { 237 catchsql { 238 PRAGMA integrity_check 239 } 240 } {1 {no such collation sequence: string_compare}} 241} 242do_test collate3-3.9 { 243 catchsql { 244 SELECT * FROM collate3t1; 245 } 246} {0 {}} 247do_test collate3-3.10 { 248 catchsql { 249 SELECT * FROM collate3t1 ORDER BY 1 COLLATE string_compare; 250 } 251} {1 {no such collation sequence: string_compare}} 252do_test collate3-3.11 { 253 catchsql { 254 SELECT * FROM collate3t1 ORDER BY c1; 255 } 256} {1 {no such collation sequence: string_compare}} 257do_test collate3-3.12 { 258 catchsql { 259 SELECT * FROM collate3t1 WHERE c1 = 'xxx'; 260 } 261} {1 {no such collation sequence: string_compare}} 262do_test collate3-3.13 { 263 catchsql { 264 CREATE TABLE collate3t2(c1 COLLATE string_compare); 265 } 266} {1 {no such collation sequence: string_compare}} 267do_test collate3-3.14 { 268 catchsql { 269 CREATE INDEX collate3t1_i2 ON collate3t1(c1); 270 } 271} {1 {no such collation sequence: string_compare}} 272do_test collate3-3.15 { 273 execsql { 274 DROP TABLE collate3t1; 275 } 276} {} 277 278# Check we can create an index that uses an explicit collation 279# sequence and then close and re-open the database. 280do_test collate3-4.6 { 281 db collate user_defined "string compare" 282 execsql { 283 CREATE TABLE collate3t1(a, b); 284 INSERT INTO collate3t1 VALUES('hello', NULL); 285 CREATE INDEX collate3i1 ON collate3t1(a COLLATE user_defined); 286 } 287} {} 288do_test collate3-4.7 { 289 db close 290 sqlite3 db test.db 291 catchsql { 292 SELECT * FROM collate3t1 ORDER BY a COLLATE user_defined; 293 } 294} {1 {no such collation sequence: user_defined}} 295do_test collate3-4.8 { 296 db collate user_defined "string compare" 297 catchsql { 298 SELECT * FROM collate3t1 ORDER BY a COLLATE user_defined; 299 } 300} {0 {hello {}}} 301do_test collate3-4.8 { 302 db close 303 lindex [catch { 304 sqlite3 db test.db 305 }] 0 306} {0} 307do_test collate3-4.8 { 308 execsql { 309 DROP TABLE collate3t1; 310 } 311} {} 312 313# Compare strings as numbers. 314proc numeric_compare {lhs rhs} { 315 if {$rhs > $lhs} { 316 set res -1 317 } else { 318 set res [expr ($lhs > $rhs)?1:0] 319 } 320 return $res 321} 322 323# Check we can create a view that uses an explicit collation 324# sequence and then close and re-open the database. 325ifcapable view { 326do_test collate3-4.9 { 327 db collate user_defined numeric_compare 328 execsql { 329 CREATE TABLE collate3t1(a, b); 330 INSERT INTO collate3t1 VALUES('2', NULL); 331 INSERT INTO collate3t1 VALUES('101', NULL); 332 INSERT INTO collate3t1 VALUES('12', NULL); 333 CREATE VIEW collate3v1 AS SELECT * FROM collate3t1 334 ORDER BY 1 COLLATE user_defined; 335 SELECT * FROM collate3v1; 336 } 337} {2 {} 12 {} 101 {}} 338do_test collate3-4.10 { 339 db close 340 sqlite3 db test.db 341 catchsql { 342 SELECT * FROM collate3v1; 343 } 344} {1 {no such collation sequence: user_defined}} 345do_test collate3-4.11 { 346 db collate user_defined numeric_compare 347 catchsql { 348 SELECT * FROM collate3v1; 349 } 350} {0 {2 {} 12 {} 101 {}}} 351do_test collate3-4.12 { 352 execsql { 353 DROP TABLE collate3t1; 354 } 355} {} 356} ;# ifcapable view 357 358# 359# Test the collation factory. In the code, the "no such collation sequence" 360# message is only generated in two places. So these tests just test that 361# the collation factory can be called once from each of those points. 362# 363do_test collate3-5.0 { 364 catchsql { 365 CREATE TABLE collate3t1(a); 366 INSERT INTO collate3t1 VALUES(10); 367 SELECT a FROM collate3t1 ORDER BY 1 COLLATE unk; 368 } 369} {1 {no such collation sequence: unk}} 370do_test collate3-5.1 { 371 set ::cfact_cnt 0 372 proc cfact {nm} { 373 db collate $nm {string compare} 374 incr ::cfact_cnt 375 } 376 db collation_needed cfact 377} {} 378do_test collate3-5.2 { 379 catchsql { 380 SELECT a FROM collate3t1 ORDER BY 1 COLLATE unk; 381 } 382} {0 10} 383do_test collate3-5.3 { 384 set ::cfact_cnt 385} {1} 386do_test collate3-5.4 { 387 catchsql { 388 SELECT a FROM collate3t1 ORDER BY 1 COLLATE unk; 389 } 390} {0 10} 391do_test collate3-5.5 { 392 set ::cfact_cnt 393} {1} 394do_test collate3-5.6 { 395 catchsql { 396 SELECT a FROM collate3t1 ORDER BY 1 COLLATE unk; 397 } 398} {0 10} 399do_test collate3-5.7 { 400 execsql { 401 DROP TABLE collate3t1; 402 CREATE TABLE collate3t1(a COLLATE unk); 403 } 404 db close 405 sqlite3 db test.db 406 catchsql { 407 SELECT a FROM collate3t1 ORDER BY 1; 408 } 409} {1 {no such collation sequence: unk}} 410do_test collate3-5.8 { 411 set ::cfact_cnt 0 412 proc cfact {nm} { 413 db collate $nm {string compare} 414 incr ::cfact_cnt 415 } 416 db collation_needed cfact 417 catchsql { 418 SELECT a FROM collate3t1 ORDER BY 1; 419 } 420} {0 {}} 421 422do_test collate3-5.9 { 423 execsql { 424 DROP TABLE collate3t1; 425 } 426} {} 427 428finish_test 429