xref: /sqlite-3.40.0/test/collate3.test (revision 49d642db)
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