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