xref: /sqlite-3.40.0/test/collate3.test (revision ef4ac8f9)
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.3 2004/06/19 00:16:31 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 {
113  catchsql {
114    SELECT * FROM collate3t1 GROUP BY c1;
115  }
116} {1 {no such collation sequence: string_compare}}
117do_test collate3-2.8 {
118  catchsql {
119    SELECT DISTINCT c1 FROM collate3t1;
120  }
121} {1 {no such collation sequence: string_compare}}
122
123do_test collate3-2.9 {
124  catchsql {
125    SELECT c1 FROM collate3t1 UNION SELECT c1 FROM collate3t1;
126  }
127} {1 {no such collation sequence: string_compare}}
128do_test collate3-2.10 {
129  catchsql {
130    SELECT c1 FROM collate3t1 EXCEPT SELECT c1 FROM collate3t1;
131  }
132} {1 {no such collation sequence: string_compare}}
133do_test collate3-2.11 {
134  catchsql {
135    SELECT c1 FROM collate3t1 INTERSECT SELECT c1 FROM collate3t1;
136  }
137} {1 {no such collation sequence: string_compare}}
138do_test collate3-2.12 {
139  catchsql {
140    SELECT c1 FROM collate3t1 UNION ALL SELECT c1 FROM collate3t1;
141  }
142} {0 {}}
143do_test collate3-2.13 {
144  catchsql {
145    SELECT 10 UNION ALL SELECT 20 ORDER BY 1 COLLATE string_compare;
146  }
147} {1 {no such collation sequence: string_compare}}
148do_test collate3-2.14 {
149  catchsql {
150    SELECT 10 INTERSECT SELECT 20 ORDER BY 1 COLLATE string_compare;
151  }
152} {1 {no such collation sequence: string_compare}}
153do_test collate3-2.15 {
154  catchsql {
155    SELECT 10 EXCEPT SELECT 20 ORDER BY 1 COLLATE string_compare;
156  }
157} {1 {no such collation sequence: string_compare}}
158do_test collate3-2.16 {
159  catchsql {
160    SELECT 10 UNION SELECT 20 ORDER BY 1 COLLATE string_compare;
161  }
162} {1 {no such collation sequence: string_compare}}
163do_test collate3-2.17 {
164  catchsql {
165    SELECT c1 FROM collate3t1 UNION ALL SELECT c1 FROM collate3t1 ORDER BY 1;
166  }
167} {1 {no such collation sequence: string_compare}}
168
169#
170# Create an index that uses a collation sequence then close and
171# re-open the database without re-registering the collation
172# sequence. Then check that for the table with the index
173# * An INSERT fails,
174# * An UPDATE on the column with the index fails,
175# * An UPDATE on a different column succeeds.
176# * A DELETE with a WHERE clause fails
177# * A DELETE without a WHERE clause succeeds
178#
179# Also, ensure that the restrictions tested by collate3-2.* still
180# apply after the index has been created.
181#
182do_test collate3-3.0 {
183  db collate string_compare {string compare}
184  execsql {
185    CREATE INDEX collate3t1_i1 ON collate3t1(c1);
186    INSERT INTO collate3t1 VALUES('xxx', 'yyy');
187  }
188  db close
189  sqlite3 db test.db
190  expr 0
191} 0
192db eval {select * from collate3t1}
193breakpoint
194do_test collate3-3.1 {
195  catchsql {
196    INSERT INTO collate3t1 VALUES('xxx', 0);
197  }
198} {1 {no such collation sequence: string_compare}}
199do_test collate3-3.2 {
200  catchsql {
201    UPDATE collate3t1 SET c1 = 'xxx';
202  }
203} {1 {no such collation sequence: string_compare}}
204do_test collate3-3.3 {
205  catchsql {
206    UPDATE collate3t1 SET c2 = 'xxx';
207  }
208} {0 {}}
209do_test collate3-3.4 {
210  catchsql {
211    DELETE FROM collate3t1 WHERE 1;
212  }
213} {1 {no such collation sequence: string_compare}}
214do_test collate3-3.5 {
215  catchsql {
216    SELECT * FROM collate3t1;
217  }
218} {0 {xxx xxx}}
219do_test collate3-3.6 {
220  catchsql {
221    DELETE FROM collate3t1;
222  }
223} {0 {}}
224do_test collate3-3.8 {
225  catchsql {
226    PRAGMA integrity_check
227  }
228} {1 {no such collation sequence: string_compare}}
229do_test collate3-3.9 {
230  catchsql {
231    SELECT * FROM collate3t1;
232  }
233} {0 {}}
234do_test collate3-3.10 {
235  catchsql {
236    SELECT * FROM collate3t1 ORDER BY 1 COLLATE string_compare;
237  }
238} {1 {no such collation sequence: string_compare}}
239do_test collate3-3.11 {
240  catchsql {
241    SELECT * FROM collate3t1 ORDER BY c1;
242  }
243} {1 {no such collation sequence: string_compare}}
244do_test collate3-3.12 {
245  catchsql {
246    SELECT * FROM collate3t1 WHERE c1 = 'xxx';
247  }
248} {1 {no such collation sequence: string_compare}}
249do_test collate3-3.13 {
250  catchsql {
251    CREATE TABLE collate3t2(c1 COLLATE string_compare);
252  }
253} {1 {no such collation sequence: string_compare}}
254do_test collate3-3.14 {
255  catchsql {
256    CREATE INDEX collate3t1_i2 ON collate3t1(c1);
257  }
258} {1 {no such collation sequence: string_compare}}
259do_test collate3-3.15 {
260  execsql {
261    DROP TABLE collate3t1;
262  }
263} {}
264
265# Check we can create an index that uses an explicit collation
266# sequence and then close and re-open the database.
267do_test collate3-4.6 {
268  db collate user_defined "string compare"
269  execsql {
270    CREATE TABLE collate3t1(a, b);
271    INSERT INTO collate3t1 VALUES('hello', NULL);
272    CREATE INDEX collate3i1 ON collate3t1(a COLLATE user_defined);
273  }
274} {}
275do_test collate3-4.7 {
276  db close
277  sqlite3 db test.db
278  catchsql {
279    SELECT * FROM collate3t1 ORDER BY a COLLATE user_defined;
280  }
281} {1 {no such collation sequence: user_defined}}
282do_test collate3-4.8 {
283  db collate user_defined "string compare"
284  catchsql {
285    SELECT * FROM collate3t1 ORDER BY a COLLATE user_defined;
286  }
287} {0 {hello {}}}
288do_test collate3-4.8 {
289  db close
290  lindex [catch {
291    sqlite3 db test.db
292  }] 0
293} {0}
294do_test collate3-4.8 {
295  execsql {
296    DROP TABLE collate3t1;
297  }
298} {}
299
300# Compare strings as numbers.
301proc numeric_compare {lhs rhs} {
302  if {$rhs > $lhs} {
303    set res -1
304  } else {
305    set res [expr ($lhs > $rhs)?1:0]
306  }
307  return $res
308}
309
310# Check we can create a view that uses an explicit collation
311# sequence and then close and re-open the database.
312do_test collate3-4.9 {
313  db collate user_defined numeric_compare
314  execsql {
315    CREATE TABLE collate3t1(a, b);
316    INSERT INTO collate3t1 VALUES('2', NULL);
317    INSERT INTO collate3t1 VALUES('101', NULL);
318    INSERT INTO collate3t1 VALUES('12', NULL);
319    CREATE VIEW collate3v1 AS SELECT * FROM collate3t1
320        ORDER BY 1 COLLATE user_defined;
321    SELECT * FROM collate3v1;
322  }
323} {2 {} 12 {} 101 {}}
324do_test collate3-4.10 {
325  db close
326  sqlite3 db test.db
327  catchsql {
328    SELECT * FROM collate3v1;
329  }
330} {1 {no such collation sequence: user_defined}}
331do_test collate3-4.11 {
332  db collate user_defined numeric_compare
333  catchsql {
334    SELECT * FROM collate3v1;
335  }
336} {0 {2 {} 12 {} 101 {}}}
337do_test collate3-4.12 {
338  execsql {
339    DROP TABLE collate3t1;
340  }
341} {}
342
343#
344# Test the collation factory. In the code, the "no such collation sequence"
345# message is only generated in two places. So these tests just test that
346# the collation factory can be called once from each of those points.
347#
348do_test collate3-5.0 {
349  catchsql {
350    CREATE TABLE collate3t1(a);
351    INSERT INTO collate3t1 VALUES(10);
352    SELECT a FROM collate3t1 ORDER BY 1 COLLATE unk;
353  }
354} {1 {no such collation sequence: unk}}
355do_test collate3-5.1 {
356  set ::cfact_cnt 0
357  proc cfact {nm} {
358    db collate $nm {string compare}
359    incr ::cfact_cnt
360  }
361  db collation_needed cfact
362} {}
363do_test collate3-5.2 {
364  catchsql {
365    SELECT a FROM collate3t1 ORDER BY 1 COLLATE unk;
366  }
367} {0 10}
368do_test collate3-5.3 {
369  set ::cfact_cnt
370} {1}
371do_test collate3-5.4 {
372  catchsql {
373    SELECT a FROM collate3t1 ORDER BY 1 COLLATE unk;
374  }
375} {0 10}
376do_test collate3-5.5 {
377  set ::cfact_cnt
378} {1}
379do_test collate3-5.6 {
380  catchsql {
381    SELECT a FROM collate3t1 ORDER BY 1 COLLATE unk;
382  }
383} {0 10}
384do_test collate3-5.7 {
385  execsql {
386    DROP TABLE collate3t1;
387    CREATE TABLE collate3t1(a COLLATE unk);
388  }
389  db close
390  sqlite3 db test.db
391  catchsql {
392    SELECT a FROM collate3t1 ORDER BY 1;
393  }
394} {1 {no such collation sequence: unk}}
395do_test collate3-5.8 {
396  set ::cfact_cnt 0
397  proc cfact {nm} {
398    db collate $nm {string compare}
399    incr ::cfact_cnt
400  }
401  db collation_needed cfact
402  catchsql {
403    SELECT a FROM collate3t1 ORDER BY 1;
404  }
405} {0 {}}
406
407do_test collate3-5.9 {
408  execsql {
409    DROP TABLE collate3t1;
410  }
411} {}
412
413finish_test
414