xref: /sqlite-3.40.0/test/collate3.test (revision 7aa3ebee)
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.13 2008/08/20 16:35:10 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 UNIQUE);
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.1.2 {
44  catchsql {
45    SELECT DISTINCT c1 COLLATE garbage FROM collate3t1;
46  }
47} {1 {no such collation sequence: garbage}}
48do_test collate3-1.2 {
49  catchsql {
50    CREATE TABLE collate3t2(c1 collate garbage);
51  }
52} {1 {no such collation sequence: garbage}}
53do_test collate3-1.3 {
54  catchsql {
55    CREATE INDEX collate3i1 ON collate3t1(c1 COLLATE garbage);
56  }
57} {1 {no such collation sequence: garbage}}
58
59execsql {
60  DROP TABLE collate3t1;
61}
62
63proc caseless {a b} { string compare -nocase $a $b }
64do_test collate3-1.4 {
65  db collate caseless caseless
66  execsql {
67    CREATE TABLE t1(a COLLATE caseless);
68    INSERT INTO t1 VALUES('Abc2');
69    INSERT INTO t1 VALUES('abc1');
70    INSERT INTO t1 VALUES('aBc3');
71  }
72  execsql { SELECT * FROM t1 ORDER BY a }
73} {abc1 Abc2 aBc3}
74
75do_test collate3-1.5 {
76  db close
77  sqlite3 db test.db
78  catchsql { SELECT * FROM t1 ORDER BY a }
79} {1 {no such collation sequence: caseless}}
80
81do_test collate3-1.6.1 {
82  db collate caseless caseless
83  execsql { CREATE INDEX i1 ON t1(a) }
84  execsql { SELECT * FROM t1 ORDER BY a }
85} {abc1 Abc2 aBc3}
86
87do_test collate3-1.6.2 {
88  db close
89  sqlite3 db test.db
90  catchsql { SELECT * FROM t1 ORDER BY a }
91} {1 {no such collation sequence: caseless}}
92
93do_test collate3-1.6.3 {
94  db close
95  sqlite3 db test.db
96  catchsql { PRAGMA integrity_check }
97} {1 {no such collation sequence: caseless}}
98
99do_test collate3-1.6.4 {
100  db close
101  sqlite3 db test.db
102  catchsql { REINDEX }
103} {1 {no such collation sequence: caseless}}
104
105do_test collate3-1.7.1 {
106  db collate caseless caseless
107  execsql {
108    DROP TABLE t1;
109    CREATE TABLE t1(a);
110    CREATE INDEX i1 ON t1(a COLLATE caseless);
111    INSERT INTO t1 VALUES('Abc2');
112    INSERT INTO t1 VALUES('abc1');
113    INSERT INTO t1 VALUES('aBc3');
114    SELECT * FROM t1 ORDER BY a COLLATE caseless;
115  }
116} {abc1 Abc2 aBc3}
117
118do_test collate3-1.7.2 {
119  db close
120  sqlite3 db test.db
121  catchsql { SELECT * FROM t1 ORDER BY a COLLATE caseless}
122} {1 {no such collation sequence: caseless}}
123
124do_test collate3-1.7.4 {
125  db close
126  sqlite3 db test.db
127  catchsql { REINDEX }
128} {1 {no such collation sequence: caseless}}
129
130do_test collate3-1.7.3 {
131  db close
132  sqlite3 db test.db
133  catchsql { PRAGMA integrity_check }
134} {1 {no such collation sequence: caseless}}
135
136do_test collate3-1.7.4 {
137  db close
138  sqlite3 db test.db
139  catchsql { REINDEX }
140} {1 {no such collation sequence: caseless}}
141
142do_test collate3-1.7.5 {
143  db close
144  sqlite3 db test.db
145  db collate caseless caseless
146  catchsql { PRAGMA integrity_check }
147} {0 ok}
148
149proc needed {nm} { db collate caseless caseless }
150do_test collate3-1.7.6 {
151  db close
152  sqlite3 db test.db
153  db collation_needed needed
154  catchsql { PRAGMA integrity_check }
155} {0 ok}
156
157do_test collate3-1.8 {
158  execsql { DROP TABLE t1 }
159} {}
160
161#
162# Create a table with a default collation sequence, then close
163# and re-open the database without re-registering the collation
164# sequence. Then make sure the library stops us from using
165# the collation sequence in:
166# * an explicitly collated ORDER BY
167# * an ORDER BY that uses the default collation sequence
168# * an expression (=)
169# * a CREATE TABLE statement
170# * a CREATE INDEX statement that uses a default collation sequence
171# * a GROUP BY that uses the default collation sequence
172# * a SELECT DISTINCT that uses the default collation sequence
173# * Compound SELECTs that uses the default collation sequence
174# * An ORDER BY on a compound SELECT with an explicit ORDER BY.
175#
176do_test collate3-2.0 {
177  db collate string_compare {string compare}
178  execsql {
179    CREATE TABLE collate3t1(c1 COLLATE string_compare, c2);
180  }
181  db close
182  sqlite3 db test.db
183  expr 0
184} 0
185do_test collate3-2.1 {
186  catchsql {
187    SELECT * FROM collate3t1 ORDER BY 1 COLLATE string_compare;
188  }
189} {1 {no such collation sequence: string_compare}}
190do_test collate3-2.2 {
191  catchsql {
192    SELECT * FROM collate3t1 ORDER BY c1;
193  }
194} {1 {no such collation sequence: string_compare}}
195do_test collate3-2.3 {
196  catchsql {
197    SELECT * FROM collate3t1 WHERE c1 = 'xxx';
198  }
199} {1 {no such collation sequence: string_compare}}
200do_test collate3-2.4 {
201  catchsql {
202    CREATE TABLE collate3t2(c1 COLLATE string_compare);
203  }
204} {1 {no such collation sequence: string_compare}}
205do_test collate3-2.5 {
206  catchsql {
207    CREATE INDEX collate3t1_i1 ON collate3t1(c1);
208  }
209} {1 {no such collation sequence: string_compare}}
210do_test collate3-2.6 {
211  catchsql {
212    SELECT * FROM collate3t1;
213  }
214} {0 {}}
215do_test collate3-2.7.1 {
216  catchsql {
217    SELECT count(*) FROM collate3t1 GROUP BY c1;
218  }
219} {1 {no such collation sequence: string_compare}}
220# do_test collate3-2.7.2 {
221#   catchsql {
222#     SELECT * FROM collate3t1 GROUP BY c1;
223#   }
224# } {1 {GROUP BY may only be used on aggregate queries}}
225do_test collate3-2.7.2 {
226  catchsql {
227    SELECT * FROM collate3t1 GROUP BY c1;
228  }
229} {1 {no such collation sequence: string_compare}}
230do_test collate3-2.8 {
231  catchsql {
232    SELECT DISTINCT c1 FROM collate3t1;
233  }
234} {1 {no such collation sequence: string_compare}}
235
236ifcapable compound {
237  do_test collate3-2.9 {
238    catchsql {
239      SELECT c1 FROM collate3t1 UNION SELECT c1 FROM collate3t1;
240    }
241  } {1 {no such collation sequence: string_compare}}
242  do_test collate3-2.10 {
243    catchsql {
244      SELECT c1 FROM collate3t1 EXCEPT SELECT c1 FROM collate3t1;
245    }
246  } {1 {no such collation sequence: string_compare}}
247  do_test collate3-2.11 {
248    catchsql {
249      SELECT c1 FROM collate3t1 INTERSECT SELECT c1 FROM collate3t1;
250    }
251  } {1 {no such collation sequence: string_compare}}
252  do_test collate3-2.12 {
253    catchsql {
254      SELECT c1 FROM collate3t1 UNION ALL SELECT c1 FROM collate3t1;
255    }
256  } {0 {}}
257  do_test collate3-2.13 {
258    catchsql {
259      SELECT 10 UNION ALL SELECT 20 ORDER BY 1 COLLATE string_compare;
260    }
261  } {1 {no such collation sequence: string_compare}}
262  do_test collate3-2.14 {
263    catchsql {
264      SELECT 10 INTERSECT SELECT 20 ORDER BY 1 COLLATE string_compare;
265    }
266  } {1 {no such collation sequence: string_compare}}
267  do_test collate3-2.15 {
268    catchsql {
269      SELECT 10 EXCEPT SELECT 20 ORDER BY 1 COLLATE string_compare;
270    }
271  } {1 {no such collation sequence: string_compare}}
272  do_test collate3-2.16 {
273    catchsql {
274      SELECT 10 UNION SELECT 20 ORDER BY 1 COLLATE string_compare;
275    }
276  } {1 {no such collation sequence: string_compare}}
277  do_test collate3-2.17 {
278    catchsql {
279      SELECT c1 FROM collate3t1 UNION ALL SELECT c1 FROM collate3t1 ORDER BY 1;
280    }
281  } {1 {no such collation sequence: string_compare}}
282} ;# ifcapable compound
283
284#
285# Create an index that uses a collation sequence then close and
286# re-open the database without re-registering the collation
287# sequence. Then check that for the table with the index
288# * An INSERT fails,
289# * An UPDATE on the column with the index fails,
290# * An UPDATE on a different column succeeds.
291# * A DELETE with a WHERE clause fails
292# * A DELETE without a WHERE clause succeeds
293#
294# Also, ensure that the restrictions tested by collate3-2.* still
295# apply after the index has been created.
296#
297do_test collate3-3.0 {
298  db collate string_compare {string compare}
299  execsql {
300    CREATE INDEX collate3t1_i1 ON collate3t1(c1);
301    INSERT INTO collate3t1 VALUES('xxx', 'yyy');
302  }
303  db close
304  sqlite3 db test.db
305  expr 0
306} 0
307db eval {select * from collate3t1}
308do_test collate3-3.1 {
309  catchsql {
310    INSERT INTO collate3t1 VALUES('xxx', 0);
311  }
312} {1 {no such collation sequence: string_compare}}
313do_test collate3-3.2 {
314  catchsql {
315    UPDATE collate3t1 SET c1 = 'xxx';
316  }
317} {1 {no such collation sequence: string_compare}}
318do_test collate3-3.3 {
319  catchsql {
320    UPDATE collate3t1 SET c2 = 'xxx';
321  }
322} {0 {}}
323do_test collate3-3.4 {
324  catchsql {
325    DELETE FROM collate3t1 WHERE 1;
326  }
327} {1 {no such collation sequence: string_compare}}
328do_test collate3-3.5 {
329  catchsql {
330    SELECT * FROM collate3t1;
331  }
332} {0 {xxx xxx}}
333do_test collate3-3.6 {
334  catchsql {
335    DELETE FROM collate3t1;
336  }
337} {0 {}}
338ifcapable {integrityck} {
339  do_test collate3-3.8 {
340    catchsql {
341      PRAGMA integrity_check
342    }
343  } {1 {no such collation sequence: string_compare}}
344}
345do_test collate3-3.9 {
346  catchsql {
347    SELECT * FROM collate3t1;
348  }
349} {0 {}}
350do_test collate3-3.10 {
351  catchsql {
352    SELECT * FROM collate3t1 ORDER BY 1 COLLATE string_compare;
353  }
354} {1 {no such collation sequence: string_compare}}
355do_test collate3-3.11 {
356  catchsql {
357    SELECT * FROM collate3t1 ORDER BY c1;
358  }
359} {1 {no such collation sequence: string_compare}}
360do_test collate3-3.12 {
361  catchsql {
362    SELECT * FROM collate3t1 WHERE c1 = 'xxx';
363  }
364} {1 {no such collation sequence: string_compare}}
365do_test collate3-3.13 {
366  catchsql {
367    CREATE TABLE collate3t2(c1 COLLATE string_compare);
368  }
369} {1 {no such collation sequence: string_compare}}
370do_test collate3-3.14 {
371  catchsql {
372    CREATE INDEX collate3t1_i2 ON collate3t1(c1);
373  }
374} {1 {no such collation sequence: string_compare}}
375do_test collate3-3.15 {
376  execsql {
377    DROP TABLE collate3t1;
378  }
379} {}
380
381# Check we can create an index that uses an explicit collation
382# sequence and then close and re-open the database.
383do_test collate3-4.6 {
384  db collate user_defined "string compare"
385  execsql {
386    CREATE TABLE collate3t1(a, b);
387    INSERT INTO collate3t1 VALUES('hello', NULL);
388    CREATE INDEX collate3i1 ON collate3t1(a COLLATE user_defined);
389  }
390} {}
391do_test collate3-4.7 {
392  db close
393  sqlite3 db test.db
394  catchsql {
395    SELECT * FROM collate3t1 ORDER BY a COLLATE user_defined;
396  }
397} {1 {no such collation sequence: user_defined}}
398do_test collate3-4.8.1 {
399  db collate user_defined "string compare"
400  catchsql {
401    SELECT * FROM collate3t1 ORDER BY a COLLATE user_defined;
402  }
403} {0 {hello {}}}
404do_test collate3-4.8.2 {
405  db close
406  lindex [catch {
407    sqlite3 db test.db
408  }] 0
409} {0}
410do_test collate3-4.8.3 {
411  execsql {
412    DROP TABLE collate3t1;
413  }
414} {}
415
416# Compare strings as numbers.
417proc numeric_compare {lhs rhs} {
418  if {$rhs > $lhs} {
419    set res -1
420  } else {
421    set res [expr ($lhs > $rhs)?1:0]
422  }
423  return $res
424}
425
426# Check we can create a view that uses an explicit collation
427# sequence and then close and re-open the database.
428ifcapable view {
429do_test collate3-4.9 {
430  db collate user_defined numeric_compare
431  execsql {
432    CREATE TABLE collate3t1(a, b);
433    INSERT INTO collate3t1 VALUES('2', NULL);
434    INSERT INTO collate3t1 VALUES('101', NULL);
435    INSERT INTO collate3t1 VALUES('12', NULL);
436    CREATE VIEW collate3v1 AS SELECT * FROM collate3t1
437        ORDER BY 1 COLLATE user_defined;
438    SELECT * FROM collate3v1;
439  }
440} {2 {} 12 {} 101 {}}
441do_test collate3-4.10 {
442  db close
443  sqlite3 db test.db
444  catchsql {
445    SELECT * FROM collate3v1;
446  }
447} {1 {no such collation sequence: user_defined}}
448do_test collate3-4.11 {
449  db collate user_defined numeric_compare
450  catchsql {
451    SELECT * FROM collate3v1;
452  }
453} {0 {2 {} 12 {} 101 {}}}
454do_test collate3-4.12 {
455  execsql {
456    DROP TABLE collate3t1;
457  }
458} {}
459} ;# ifcapable view
460
461#
462# Test the collation factory. In the code, the "no such collation sequence"
463# message is only generated in two places. So these tests just test that
464# the collation factory can be called once from each of those points.
465#
466do_test collate3-5.0 {
467  catchsql {
468    CREATE TABLE collate3t1(a);
469    INSERT INTO collate3t1 VALUES(10);
470    SELECT a FROM collate3t1 ORDER BY 1 COLLATE unk;
471  }
472} {1 {no such collation sequence: unk}}
473do_test collate3-5.1 {
474  set ::cfact_cnt 0
475  proc cfact {nm} {
476    db collate $nm {string compare}
477    incr ::cfact_cnt
478  }
479  db collation_needed cfact
480} {}
481do_test collate3-5.2 {
482  catchsql {
483    SELECT a FROM collate3t1 ORDER BY 1 COLLATE unk;
484  }
485} {0 10}
486do_test collate3-5.3 {
487  set ::cfact_cnt
488} {1}
489do_test collate3-5.4 {
490  catchsql {
491    SELECT a FROM collate3t1 ORDER BY 1 COLLATE unk;
492  }
493} {0 10}
494do_test collate3-5.5 {
495  set ::cfact_cnt
496} {1}
497do_test collate3-5.6 {
498  catchsql {
499    SELECT a FROM collate3t1 ORDER BY 1 COLLATE unk;
500  }
501} {0 10}
502do_test collate3-5.7 {
503  execsql {
504    DROP TABLE collate3t1;
505    CREATE TABLE collate3t1(a COLLATE unk);
506  }
507  db close
508  sqlite3 db test.db
509  catchsql {
510    SELECT a FROM collate3t1 ORDER BY 1;
511  }
512} {1 {no such collation sequence: unk}}
513do_test collate3-5.8 {
514  set ::cfact_cnt 0
515  proc cfact {nm} {
516    db collate $nm {string compare}
517    incr ::cfact_cnt
518  }
519  db collation_needed cfact
520  catchsql {
521    SELECT a FROM collate3t1 ORDER BY 1;
522  }
523} {0 {}}
524
525do_test collate3-5.9 {
526  execsql {
527    DROP TABLE collate3t1;
528  }
529} {}
530
531finish_test
532