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