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