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.7 2005/01/03 02:26:55 drh 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}} 117do_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.8 { 123 catchsql { 124 SELECT DISTINCT c1 FROM collate3t1; 125 } 126} {1 {no such collation sequence: string_compare}} 127 128ifcapable compound { 129do_test collate3-2.9 { 130 catchsql { 131 SELECT c1 FROM collate3t1 UNION SELECT c1 FROM collate3t1; 132 } 133} {1 {no such collation sequence: string_compare}} 134do_test collate3-2.10 { 135 catchsql { 136 SELECT c1 FROM collate3t1 EXCEPT SELECT c1 FROM collate3t1; 137 } 138} {1 {no such collation sequence: string_compare}} 139do_test collate3-2.11 { 140 catchsql { 141 SELECT c1 FROM collate3t1 INTERSECT SELECT c1 FROM collate3t1; 142 } 143} {1 {no such collation sequence: string_compare}} 144do_test collate3-2.12 { 145 catchsql { 146 SELECT c1 FROM collate3t1 UNION ALL SELECT c1 FROM collate3t1; 147 } 148} {0 {}} 149do_test collate3-2.13 { 150 catchsql { 151 SELECT 10 UNION ALL SELECT 20 ORDER BY 1 COLLATE string_compare; 152 } 153} {1 {no such collation sequence: string_compare}} 154do_test collate3-2.14 { 155 catchsql { 156 SELECT 10 INTERSECT SELECT 20 ORDER BY 1 COLLATE string_compare; 157 } 158} {1 {no such collation sequence: string_compare}} 159do_test collate3-2.15 { 160 catchsql { 161 SELECT 10 EXCEPT SELECT 20 ORDER BY 1 COLLATE string_compare; 162 } 163} {1 {no such collation sequence: string_compare}} 164do_test collate3-2.16 { 165 catchsql { 166 SELECT 10 UNION SELECT 20 ORDER BY 1 COLLATE string_compare; 167 } 168} {1 {no such collation sequence: string_compare}} 169do_test collate3-2.17 { 170 catchsql { 171 SELECT c1 FROM collate3t1 UNION ALL SELECT c1 FROM collate3t1 ORDER BY 1; 172 } 173} {1 {no such collation sequence: string_compare}} 174} ;# ifcapable compound 175 176# 177# Create an index that uses a collation sequence then close and 178# re-open the database without re-registering the collation 179# sequence. Then check that for the table with the index 180# * An INSERT fails, 181# * An UPDATE on the column with the index fails, 182# * An UPDATE on a different column succeeds. 183# * A DELETE with a WHERE clause fails 184# * A DELETE without a WHERE clause succeeds 185# 186# Also, ensure that the restrictions tested by collate3-2.* still 187# apply after the index has been created. 188# 189do_test collate3-3.0 { 190 db collate string_compare {string compare} 191 execsql { 192 CREATE INDEX collate3t1_i1 ON collate3t1(c1); 193 INSERT INTO collate3t1 VALUES('xxx', 'yyy'); 194 } 195 db close 196 sqlite3 db test.db 197 expr 0 198} 0 199db eval {select * from collate3t1} 200breakpoint 201do_test collate3-3.1 { 202 catchsql { 203 INSERT INTO collate3t1 VALUES('xxx', 0); 204 } 205} {1 {no such collation sequence: string_compare}} 206do_test collate3-3.2 { 207 catchsql { 208 UPDATE collate3t1 SET c1 = 'xxx'; 209 } 210} {1 {no such collation sequence: string_compare}} 211do_test collate3-3.3 { 212 catchsql { 213 UPDATE collate3t1 SET c2 = 'xxx'; 214 } 215} {0 {}} 216do_test collate3-3.4 { 217 catchsql { 218 DELETE FROM collate3t1 WHERE 1; 219 } 220} {1 {no such collation sequence: string_compare}} 221do_test collate3-3.5 { 222 catchsql { 223 SELECT * FROM collate3t1; 224 } 225} {0 {xxx xxx}} 226do_test collate3-3.6 { 227 catchsql { 228 DELETE FROM collate3t1; 229 } 230} {0 {}} 231ifcapable {integrityck} { 232 do_test collate3-3.8 { 233 catchsql { 234 PRAGMA integrity_check 235 } 236 } {1 {no such collation sequence: string_compare}} 237} 238do_test collate3-3.9 { 239 catchsql { 240 SELECT * FROM collate3t1; 241 } 242} {0 {}} 243do_test collate3-3.10 { 244 catchsql { 245 SELECT * FROM collate3t1 ORDER BY 1 COLLATE string_compare; 246 } 247} {1 {no such collation sequence: string_compare}} 248do_test collate3-3.11 { 249 catchsql { 250 SELECT * FROM collate3t1 ORDER BY c1; 251 } 252} {1 {no such collation sequence: string_compare}} 253do_test collate3-3.12 { 254 catchsql { 255 SELECT * FROM collate3t1 WHERE c1 = 'xxx'; 256 } 257} {1 {no such collation sequence: string_compare}} 258do_test collate3-3.13 { 259 catchsql { 260 CREATE TABLE collate3t2(c1 COLLATE string_compare); 261 } 262} {1 {no such collation sequence: string_compare}} 263do_test collate3-3.14 { 264 catchsql { 265 CREATE INDEX collate3t1_i2 ON collate3t1(c1); 266 } 267} {1 {no such collation sequence: string_compare}} 268do_test collate3-3.15 { 269 execsql { 270 DROP TABLE collate3t1; 271 } 272} {} 273 274# Check we can create an index that uses an explicit collation 275# sequence and then close and re-open the database. 276do_test collate3-4.6 { 277 db collate user_defined "string compare" 278 execsql { 279 CREATE TABLE collate3t1(a, b); 280 INSERT INTO collate3t1 VALUES('hello', NULL); 281 CREATE INDEX collate3i1 ON collate3t1(a COLLATE user_defined); 282 } 283} {} 284do_test collate3-4.7 { 285 db close 286 sqlite3 db test.db 287 catchsql { 288 SELECT * FROM collate3t1 ORDER BY a COLLATE user_defined; 289 } 290} {1 {no such collation sequence: user_defined}} 291do_test collate3-4.8 { 292 db collate user_defined "string compare" 293 catchsql { 294 SELECT * FROM collate3t1 ORDER BY a COLLATE user_defined; 295 } 296} {0 {hello {}}} 297do_test collate3-4.8 { 298 db close 299 lindex [catch { 300 sqlite3 db test.db 301 }] 0 302} {0} 303do_test collate3-4.8 { 304 execsql { 305 DROP TABLE collate3t1; 306 } 307} {} 308 309# Compare strings as numbers. 310proc numeric_compare {lhs rhs} { 311 if {$rhs > $lhs} { 312 set res -1 313 } else { 314 set res [expr ($lhs > $rhs)?1:0] 315 } 316 return $res 317} 318 319# Check we can create a view that uses an explicit collation 320# sequence and then close and re-open the database. 321ifcapable view { 322do_test collate3-4.9 { 323 db collate user_defined numeric_compare 324 execsql { 325 CREATE TABLE collate3t1(a, b); 326 INSERT INTO collate3t1 VALUES('2', NULL); 327 INSERT INTO collate3t1 VALUES('101', NULL); 328 INSERT INTO collate3t1 VALUES('12', NULL); 329 CREATE VIEW collate3v1 AS SELECT * FROM collate3t1 330 ORDER BY 1 COLLATE user_defined; 331 SELECT * FROM collate3v1; 332 } 333} {2 {} 12 {} 101 {}} 334do_test collate3-4.10 { 335 db close 336 sqlite3 db test.db 337 catchsql { 338 SELECT * FROM collate3v1; 339 } 340} {1 {no such collation sequence: user_defined}} 341do_test collate3-4.11 { 342 db collate user_defined numeric_compare 343 catchsql { 344 SELECT * FROM collate3v1; 345 } 346} {0 {2 {} 12 {} 101 {}}} 347do_test collate3-4.12 { 348 execsql { 349 DROP TABLE collate3t1; 350 } 351} {} 352} ;# ifcapable view 353 354# 355# Test the collation factory. In the code, the "no such collation sequence" 356# message is only generated in two places. So these tests just test that 357# the collation factory can be called once from each of those points. 358# 359do_test collate3-5.0 { 360 catchsql { 361 CREATE TABLE collate3t1(a); 362 INSERT INTO collate3t1 VALUES(10); 363 SELECT a FROM collate3t1 ORDER BY 1 COLLATE unk; 364 } 365} {1 {no such collation sequence: unk}} 366do_test collate3-5.1 { 367 set ::cfact_cnt 0 368 proc cfact {nm} { 369 db collate $nm {string compare} 370 incr ::cfact_cnt 371 } 372 db collation_needed cfact 373} {} 374do_test collate3-5.2 { 375 catchsql { 376 SELECT a FROM collate3t1 ORDER BY 1 COLLATE unk; 377 } 378} {0 10} 379do_test collate3-5.3 { 380 set ::cfact_cnt 381} {1} 382do_test collate3-5.4 { 383 catchsql { 384 SELECT a FROM collate3t1 ORDER BY 1 COLLATE unk; 385 } 386} {0 10} 387do_test collate3-5.5 { 388 set ::cfact_cnt 389} {1} 390do_test collate3-5.6 { 391 catchsql { 392 SELECT a FROM collate3t1 ORDER BY 1 COLLATE unk; 393 } 394} {0 10} 395do_test collate3-5.7 { 396 execsql { 397 DROP TABLE collate3t1; 398 CREATE TABLE collate3t1(a COLLATE unk); 399 } 400 db close 401 sqlite3 db test.db 402 catchsql { 403 SELECT a FROM collate3t1 ORDER BY 1; 404 } 405} {1 {no such collation sequence: unk}} 406do_test collate3-5.8 { 407 set ::cfact_cnt 0 408 proc cfact {nm} { 409 db collate $nm {string compare} 410 incr ::cfact_cnt 411 } 412 db collation_needed cfact 413 catchsql { 414 SELECT a FROM collate3t1 ORDER BY 1; 415 } 416} {0 {}} 417 418do_test collate3-5.9 { 419 execsql { 420 DROP TABLE collate3t1; 421 } 422} {} 423 424finish_test 425