blob: 2c051cb9a74fbdca4b60cdebace083de0cc4d090 [file] [log] [blame]
danielk1977dc1bdc42004-06-11 10:51:27 +00001# 2001 September 15
danielk1977d2b65b92004-06-10 10:51:47 +00002#
danielk1977dc1bdc42004-06-11 10:51:27 +00003# The author disclaims copyright to this source code. In place of
4# a legal notice, here is a blessing:
danielk1977d2b65b92004-06-10 10:51:47 +00005#
danielk1977dc1bdc42004-06-11 10:51:27 +00006# 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.
danielk1977d2b65b92004-06-10 10:51:47 +00009#
danielk1977dc1bdc42004-06-11 10:51:27 +000010#***********************************************************************
11# This file implements regression tests for SQLite library. The
12# focus of this script is page cache subsystem.
13#
drh7d10d5a2008-08-20 16:35:10 +000014# $Id: collate3.test,v 1.13 2008/08/20 16:35:10 drh Exp $
danielk1977d2b65b92004-06-10 10:51:47 +000015
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
dan911ce412013-05-15 15:16:50 +000058proc caseless {a b} { string compare -nocase $a $b }
59do_test collate3-1.4 {
60 db collate caseless caseless
61 execsql {
62 CREATE TABLE t1(a COLLATE caseless);
63 INSERT INTO t1 VALUES('Abc2');
64 INSERT INTO t1 VALUES('abc1');
65 INSERT INTO t1 VALUES('aBc3');
66 }
67 execsql { SELECT * FROM t1 ORDER BY a }
68} {abc1 Abc2 aBc3}
69
70do_test collate3-1.5 {
71 db close
72 sqlite3 db test.db
73 catchsql { SELECT * FROM t1 ORDER BY a }
74} {1 {no such collation sequence: caseless}}
75
76do_test collate3-1.6.1 {
77 db collate caseless caseless
78 execsql { CREATE INDEX i1 ON t1(a) }
79 execsql { SELECT * FROM t1 ORDER BY a }
80} {abc1 Abc2 aBc3}
81
82do_test collate3-1.6.2 {
83 db close
84 sqlite3 db test.db
85 catchsql { SELECT * FROM t1 ORDER BY a }
86} {1 {no such collation sequence: caseless}}
87
88do_test collate3-1.6.3 {
89 db close
90 sqlite3 db test.db
91 catchsql { PRAGMA integrity_check }
92} {1 {no such collation sequence: caseless}}
93
94do_test collate3-1.6.4 {
95 db close
96 sqlite3 db test.db
97 catchsql { REINDEX }
98} {1 {no such collation sequence: caseless}}
99
100do_test collate3-1.7.1 {
101 db collate caseless caseless
102 execsql {
103 DROP TABLE t1;
104 CREATE TABLE t1(a);
105 CREATE INDEX i1 ON t1(a COLLATE caseless);
106 INSERT INTO t1 VALUES('Abc2');
107 INSERT INTO t1 VALUES('abc1');
108 INSERT INTO t1 VALUES('aBc3');
109 SELECT * FROM t1 ORDER BY a COLLATE caseless;
110 }
111} {abc1 Abc2 aBc3}
112
113do_test collate3-1.7.2 {
114 db close
115 sqlite3 db test.db
116 catchsql { SELECT * FROM t1 ORDER BY a COLLATE caseless}
117} {1 {no such collation sequence: caseless}}
118
119do_test collate3-1.7.4 {
120 db close
121 sqlite3 db test.db
122 catchsql { REINDEX }
123} {1 {no such collation sequence: caseless}}
124
125do_test collate3-1.7.3 {
126 db close
127 sqlite3 db test.db
128 catchsql { PRAGMA integrity_check }
129} {1 {no such collation sequence: caseless}}
130
131do_test collate3-1.7.4 {
132 db close
133 sqlite3 db test.db
134 catchsql { REINDEX }
135} {1 {no such collation sequence: caseless}}
136
137do_test collate3-1.7.5 {
138 db close
139 sqlite3 db test.db
140 db collate caseless caseless
141 catchsql { PRAGMA integrity_check }
142} {0 ok}
143
dand58792e2013-05-15 16:24:46 +0000144proc needed {nm} { db collate caseless caseless }
dan911ce412013-05-15 15:16:50 +0000145do_test collate3-1.7.6 {
dand58792e2013-05-15 16:24:46 +0000146 db close
147 sqlite3 db test.db
148 db collation_needed needed
149 catchsql { PRAGMA integrity_check }
150} {0 ok}
151
152do_test collate3-1.8 {
dan911ce412013-05-15 15:16:50 +0000153 execsql { DROP TABLE t1 }
154} {}
155
danielk1977d2b65b92004-06-10 10:51:47 +0000156#
157# Create a table with a default collation sequence, then close
158# and re-open the database without re-registering the collation
159# sequence. Then make sure the library stops us from using
160# the collation sequence in:
161# * an explicitly collated ORDER BY
162# * an ORDER BY that uses the default collation sequence
163# * an expression (=)
164# * a CREATE TABLE statement
165# * a CREATE INDEX statement that uses a default collation sequence
166# * a GROUP BY that uses the default collation sequence
167# * a SELECT DISTINCT that uses the default collation sequence
168# * Compound SELECTs that uses the default collation sequence
169# * An ORDER BY on a compound SELECT with an explicit ORDER BY.
170#
171do_test collate3-2.0 {
172 db collate string_compare {string compare}
173 execsql {
174 CREATE TABLE collate3t1(c1 COLLATE string_compare, c2);
175 }
176 db close
drhef4ac8f2004-06-19 00:16:31 +0000177 sqlite3 db test.db
danielk1977d2b65b92004-06-10 10:51:47 +0000178 expr 0
179} 0
180do_test collate3-2.1 {
181 catchsql {
182 SELECT * FROM collate3t1 ORDER BY 1 COLLATE string_compare;
183 }
184} {1 {no such collation sequence: string_compare}}
185do_test collate3-2.2 {
186 catchsql {
187 SELECT * FROM collate3t1 ORDER BY c1;
188 }
189} {1 {no such collation sequence: string_compare}}
190do_test collate3-2.3 {
191 catchsql {
192 SELECT * FROM collate3t1 WHERE c1 = 'xxx';
193 }
194} {1 {no such collation sequence: string_compare}}
195do_test collate3-2.4 {
196 catchsql {
197 CREATE TABLE collate3t2(c1 COLLATE string_compare);
198 }
199} {1 {no such collation sequence: string_compare}}
200do_test collate3-2.5 {
201 catchsql {
202 CREATE INDEX collate3t1_i1 ON collate3t1(c1);
203 }
204} {1 {no such collation sequence: string_compare}}
205do_test collate3-2.6 {
206 catchsql {
207 SELECT * FROM collate3t1;
208 }
209} {0 {}}
drh49d642d2005-01-03 02:26:54 +0000210do_test collate3-2.7.1 {
211 catchsql {
212 SELECT count(*) FROM collate3t1 GROUP BY c1;
213 }
214} {1 {no such collation sequence: string_compare}}
danielk1977e2573002005-01-26 03:58:35 +0000215# do_test collate3-2.7.2 {
216# catchsql {
217# SELECT * FROM collate3t1 GROUP BY c1;
218# }
219# } {1 {GROUP BY may only be used on aggregate queries}}
drh49d642d2005-01-03 02:26:54 +0000220do_test collate3-2.7.2 {
danielk1977d2b65b92004-06-10 10:51:47 +0000221 catchsql {
222 SELECT * FROM collate3t1 GROUP BY c1;
223 }
danielk1977e2573002005-01-26 03:58:35 +0000224} {1 {no such collation sequence: string_compare}}
danielk1977d2b65b92004-06-10 10:51:47 +0000225do_test collate3-2.8 {
226 catchsql {
227 SELECT DISTINCT c1 FROM collate3t1;
228 }
229} {1 {no such collation sequence: string_compare}}
danielk1977dc1bdc42004-06-11 10:51:27 +0000230
danielk197727c77432004-11-22 13:35:41 +0000231ifcapable compound {
danielk1977b3bce662005-01-29 08:32:43 +0000232 do_test collate3-2.9 {
233 catchsql {
234 SELECT c1 FROM collate3t1 UNION SELECT c1 FROM collate3t1;
235 }
236 } {1 {no such collation sequence: string_compare}}
237 do_test collate3-2.10 {
238 catchsql {
239 SELECT c1 FROM collate3t1 EXCEPT SELECT c1 FROM collate3t1;
240 }
241 } {1 {no such collation sequence: string_compare}}
242 do_test collate3-2.11 {
243 catchsql {
244 SELECT c1 FROM collate3t1 INTERSECT SELECT c1 FROM collate3t1;
245 }
246 } {1 {no such collation sequence: string_compare}}
247 do_test collate3-2.12 {
248 catchsql {
249 SELECT c1 FROM collate3t1 UNION ALL SELECT c1 FROM collate3t1;
250 }
251 } {0 {}}
252 do_test collate3-2.13 {
253 catchsql {
254 SELECT 10 UNION ALL SELECT 20 ORDER BY 1 COLLATE string_compare;
255 }
256 } {1 {no such collation sequence: string_compare}}
257 do_test collate3-2.14 {
258 catchsql {
259 SELECT 10 INTERSECT SELECT 20 ORDER BY 1 COLLATE string_compare;
260 }
261 } {1 {no such collation sequence: string_compare}}
262 do_test collate3-2.15 {
263 catchsql {
264 SELECT 10 EXCEPT SELECT 20 ORDER BY 1 COLLATE string_compare;
265 }
266 } {1 {no such collation sequence: string_compare}}
267 do_test collate3-2.16 {
268 catchsql {
269 SELECT 10 UNION SELECT 20 ORDER BY 1 COLLATE string_compare;
270 }
271 } {1 {no such collation sequence: string_compare}}
272 do_test collate3-2.17 {
273 catchsql {
274 SELECT c1 FROM collate3t1 UNION ALL SELECT c1 FROM collate3t1 ORDER BY 1;
275 }
276 } {1 {no such collation sequence: string_compare}}
danielk197727c77432004-11-22 13:35:41 +0000277} ;# ifcapable compound
danielk1977d2b65b92004-06-10 10:51:47 +0000278
danielk1977d2b65b92004-06-10 10:51:47 +0000279#
280# Create an index that uses a collation sequence then close and
281# re-open the database without re-registering the collation
282# sequence. Then check that for the table with the index
283# * An INSERT fails,
284# * An UPDATE on the column with the index fails,
285# * An UPDATE on a different column succeeds.
286# * A DELETE with a WHERE clause fails
287# * A DELETE without a WHERE clause succeeds
288#
289# Also, ensure that the restrictions tested by collate3-2.* still
290# apply after the index has been created.
291#
292do_test collate3-3.0 {
293 db collate string_compare {string compare}
294 execsql {
295 CREATE INDEX collate3t1_i1 ON collate3t1(c1);
296 INSERT INTO collate3t1 VALUES('xxx', 'yyy');
297 }
298 db close
drhef4ac8f2004-06-19 00:16:31 +0000299 sqlite3 db test.db
danielk1977d2b65b92004-06-10 10:51:47 +0000300 expr 0
301} 0
302db eval {select * from collate3t1}
danielk1977d2b65b92004-06-10 10:51:47 +0000303do_test collate3-3.1 {
304 catchsql {
305 INSERT INTO collate3t1 VALUES('xxx', 0);
306 }
307} {1 {no such collation sequence: string_compare}}
308do_test collate3-3.2 {
309 catchsql {
310 UPDATE collate3t1 SET c1 = 'xxx';
311 }
312} {1 {no such collation sequence: string_compare}}
313do_test collate3-3.3 {
314 catchsql {
315 UPDATE collate3t1 SET c2 = 'xxx';
316 }
317} {0 {}}
318do_test collate3-3.4 {
319 catchsql {
320 DELETE FROM collate3t1 WHERE 1;
321 }
322} {1 {no such collation sequence: string_compare}}
323do_test collate3-3.5 {
324 catchsql {
325 SELECT * FROM collate3t1;
326 }
327} {0 {xxx xxx}}
328do_test collate3-3.6 {
329 catchsql {
330 DELETE FROM collate3t1;
331 }
332} {0 {}}
drh40e016e2004-11-04 14:47:11 +0000333ifcapable {integrityck} {
334 do_test collate3-3.8 {
335 catchsql {
336 PRAGMA integrity_check
337 }
338 } {1 {no such collation sequence: string_compare}}
339}
danielk1977d2b65b92004-06-10 10:51:47 +0000340do_test collate3-3.9 {
341 catchsql {
342 SELECT * FROM collate3t1;
343 }
344} {0 {}}
345do_test collate3-3.10 {
346 catchsql {
347 SELECT * FROM collate3t1 ORDER BY 1 COLLATE string_compare;
348 }
349} {1 {no such collation sequence: string_compare}}
350do_test collate3-3.11 {
351 catchsql {
352 SELECT * FROM collate3t1 ORDER BY c1;
353 }
354} {1 {no such collation sequence: string_compare}}
355do_test collate3-3.12 {
356 catchsql {
357 SELECT * FROM collate3t1 WHERE c1 = 'xxx';
358 }
359} {1 {no such collation sequence: string_compare}}
360do_test collate3-3.13 {
361 catchsql {
362 CREATE TABLE collate3t2(c1 COLLATE string_compare);
363 }
364} {1 {no such collation sequence: string_compare}}
365do_test collate3-3.14 {
366 catchsql {
367 CREATE INDEX collate3t1_i2 ON collate3t1(c1);
368 }
369} {1 {no such collation sequence: string_compare}}
370do_test collate3-3.15 {
371 execsql {
372 DROP TABLE collate3t1;
373 }
374} {}
375
376# Check we can create an index that uses an explicit collation
377# sequence and then close and re-open the database.
378do_test collate3-4.6 {
379 db collate user_defined "string compare"
380 execsql {
381 CREATE TABLE collate3t1(a, b);
382 INSERT INTO collate3t1 VALUES('hello', NULL);
383 CREATE INDEX collate3i1 ON collate3t1(a COLLATE user_defined);
384 }
385} {}
386do_test collate3-4.7 {
387 db close
drhef4ac8f2004-06-19 00:16:31 +0000388 sqlite3 db test.db
danielk1977d2b65b92004-06-10 10:51:47 +0000389 catchsql {
390 SELECT * FROM collate3t1 ORDER BY a COLLATE user_defined;
391 }
392} {1 {no such collation sequence: user_defined}}
drh7d10d5a2008-08-20 16:35:10 +0000393do_test collate3-4.8.1 {
danielk1977d2b65b92004-06-10 10:51:47 +0000394 db collate user_defined "string compare"
395 catchsql {
396 SELECT * FROM collate3t1 ORDER BY a COLLATE user_defined;
397 }
398} {0 {hello {}}}
drh7d10d5a2008-08-20 16:35:10 +0000399do_test collate3-4.8.2 {
danielk1977d2b65b92004-06-10 10:51:47 +0000400 db close
401 lindex [catch {
drhef4ac8f2004-06-19 00:16:31 +0000402 sqlite3 db test.db
danielk1977d2b65b92004-06-10 10:51:47 +0000403 }] 0
404} {0}
drh7d10d5a2008-08-20 16:35:10 +0000405do_test collate3-4.8.3 {
danielk1977d2b65b92004-06-10 10:51:47 +0000406 execsql {
407 DROP TABLE collate3t1;
408 }
409} {}
410
411# Compare strings as numbers.
412proc numeric_compare {lhs rhs} {
413 if {$rhs > $lhs} {
414 set res -1
415 } else {
416 set res [expr ($lhs > $rhs)?1:0]
417 }
418 return $res
419}
420
421# Check we can create a view that uses an explicit collation
422# sequence and then close and re-open the database.
danielk19770fa8ddb2004-11-22 08:43:32 +0000423ifcapable view {
danielk1977d2b65b92004-06-10 10:51:47 +0000424do_test collate3-4.9 {
425 db collate user_defined numeric_compare
426 execsql {
427 CREATE TABLE collate3t1(a, b);
428 INSERT INTO collate3t1 VALUES('2', NULL);
429 INSERT INTO collate3t1 VALUES('101', NULL);
430 INSERT INTO collate3t1 VALUES('12', NULL);
431 CREATE VIEW collate3v1 AS SELECT * FROM collate3t1
432 ORDER BY 1 COLLATE user_defined;
433 SELECT * FROM collate3v1;
434 }
435} {2 {} 12 {} 101 {}}
436do_test collate3-4.10 {
437 db close
drhef4ac8f2004-06-19 00:16:31 +0000438 sqlite3 db test.db
danielk1977d2b65b92004-06-10 10:51:47 +0000439 catchsql {
440 SELECT * FROM collate3v1;
441 }
442} {1 {no such collation sequence: user_defined}}
443do_test collate3-4.11 {
444 db collate user_defined numeric_compare
445 catchsql {
446 SELECT * FROM collate3v1;
447 }
448} {0 {2 {} 12 {} 101 {}}}
449do_test collate3-4.12 {
450 execsql {
451 DROP TABLE collate3t1;
452 }
453} {}
danielk19770fa8ddb2004-11-22 08:43:32 +0000454} ;# ifcapable view
danielk1977d2b65b92004-06-10 10:51:47 +0000455
456#
457# Test the collation factory. In the code, the "no such collation sequence"
458# message is only generated in two places. So these tests just test that
459# the collation factory can be called once from each of those points.
460#
461do_test collate3-5.0 {
462 catchsql {
463 CREATE TABLE collate3t1(a);
464 INSERT INTO collate3t1 VALUES(10);
465 SELECT a FROM collate3t1 ORDER BY 1 COLLATE unk;
466 }
467} {1 {no such collation sequence: unk}}
468do_test collate3-5.1 {
469 set ::cfact_cnt 0
470 proc cfact {nm} {
471 db collate $nm {string compare}
472 incr ::cfact_cnt
473 }
474 db collation_needed cfact
475} {}
476do_test collate3-5.2 {
477 catchsql {
478 SELECT a FROM collate3t1 ORDER BY 1 COLLATE unk;
479 }
480} {0 10}
481do_test collate3-5.3 {
482 set ::cfact_cnt
483} {1}
484do_test collate3-5.4 {
485 catchsql {
486 SELECT a FROM collate3t1 ORDER BY 1 COLLATE unk;
487 }
488} {0 10}
489do_test collate3-5.5 {
490 set ::cfact_cnt
491} {1}
492do_test collate3-5.6 {
493 catchsql {
494 SELECT a FROM collate3t1 ORDER BY 1 COLLATE unk;
495 }
496} {0 10}
497do_test collate3-5.7 {
498 execsql {
499 DROP TABLE collate3t1;
500 CREATE TABLE collate3t1(a COLLATE unk);
501 }
502 db close
drhef4ac8f2004-06-19 00:16:31 +0000503 sqlite3 db test.db
danielk1977d2b65b92004-06-10 10:51:47 +0000504 catchsql {
505 SELECT a FROM collate3t1 ORDER BY 1;
506 }
507} {1 {no such collation sequence: unk}}
508do_test collate3-5.8 {
509 set ::cfact_cnt 0
510 proc cfact {nm} {
511 db collate $nm {string compare}
512 incr ::cfact_cnt
513 }
514 db collation_needed cfact
515 catchsql {
516 SELECT a FROM collate3t1 ORDER BY 1;
517 }
518} {0 {}}
519
520do_test collate3-5.9 {
521 execsql {
522 DROP TABLE collate3t1;
523 }
524} {}
525
526finish_test