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