Prevent deep recursions on nested COLLATE operators.
[sqlite.git] / test / collate3.test
blob99640d05b89bee6539e7fb8754639a28fcbcc880
1 # 2001 September 15
3 # The author disclaims copyright to this source code.  In place of
4 # a legal notice, here is a blessing:
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.
10 #***********************************************************************
11 # This file implements regression tests for SQLite library.  The
12 # focus of this script is page cache subsystem.
14 # $Id: collate3.test,v 1.13 2008/08/20 16:35:10 drh Exp $
16 set testdir [file dirname $argv0]
17 source $testdir/tester.tcl
20 # Tests are organised as follows:
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.
30 # These tests ensure that when a user executes a statement with an 
31 # unknown collation sequence an error is returned.
33 do_test collate3-1.0 {
34   execsql {
35     CREATE TABLE collate3t1(c1 UNIQUE);
36   }
37 } {}
38 do_test collate3-1.1 {
39   catchsql {
40     SELECT * FROM collate3t1 ORDER BY 1 collate garbage;
41   }
42 } {1 {no such collation sequence: garbage}}
43 do_test collate3-1.1.2 {
44   catchsql {
45     SELECT DISTINCT c1 COLLATE garbage FROM collate3t1;
46   }
47 } {1 {no such collation sequence: garbage}}
48 do_test collate3-1.2 {
49   catchsql {
50     CREATE TABLE collate3t2(c1 collate garbage);
51   }
52 } {1 {no such collation sequence: garbage}}
53 do_test collate3-1.3 {
54   catchsql {
55     CREATE INDEX collate3i1 ON collate3t1(c1 COLLATE garbage);
56   }
57 } {1 {no such collation sequence: garbage}}
59 execsql {
60   DROP TABLE collate3t1;
63 proc caseless {a b} { string compare -nocase $a $b }
64 do_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}
75 do_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}}
81 do_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}
87 do_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}}
93 do_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}}
99 do_test collate3-1.6.4 {
100   db close
101   sqlite3 db test.db
102   catchsql { REINDEX }
103 } {1 {no such collation sequence: caseless}}
105 do_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}
118 do_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}}
124 do_test collate3-1.7.4 {
125   db close
126   sqlite3 db test.db
127   catchsql { REINDEX }
128 } {1 {no such collation sequence: caseless}}
130 do_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}}
136 do_test collate3-1.7.4 {
137   db close
138   sqlite3 db test.db
139   catchsql { REINDEX }
140 } {1 {no such collation sequence: caseless}}
142 do_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}
149 proc needed {nm} { db collate caseless caseless }
150 do_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}
157 do_test collate3-1.8 {
158   execsql { DROP TABLE t1 }
159 } {}
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.
176 do_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
185 do_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}} 
190 do_test collate3-2.2 {
191   catchsql {
192     SELECT * FROM collate3t1 ORDER BY c1;
193   }
194 } {1 {no such collation sequence: string_compare}} 
195 do_test collate3-2.3 {
196   catchsql {
197     SELECT * FROM collate3t1 WHERE c1 = 'xxx';
198   }
199 } {1 {no such collation sequence: string_compare}} 
200 do_test collate3-2.4 {
201   catchsql {
202     CREATE TABLE collate3t2(c1 COLLATE string_compare);
203   }
204 } {1 {no such collation sequence: string_compare}} 
205 do_test collate3-2.5 {
206   catchsql {
207     CREATE INDEX collate3t1_i1 ON collate3t1(c1);
208   }
209 } {1 {no such collation sequence: string_compare}}
210 do_test collate3-2.6 {
211   catchsql {
212     SELECT * FROM collate3t1;
213   }
214 } {0 {}}
215 do_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}}
225 do_test collate3-2.7.2 {
226   catchsql {
227     SELECT * FROM collate3t1 GROUP BY c1;
228   }
229 } {1 {no such collation sequence: string_compare}} 
230 do_test collate3-2.8 {
231   catchsql {
232     SELECT DISTINCT c1 FROM collate3t1;
233   }
234 } {1 {no such collation sequence: string_compare}} 
236 ifcapable 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
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
294 # Also, ensure that the restrictions tested by collate3-2.* still
295 # apply after the index has been created.
297 do_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
307 db eval {select * from collate3t1}
308 do_test collate3-3.1 {
309   catchsql {
310     INSERT INTO collate3t1 VALUES('xxx', 0);
311   }
312 } {1 {no such collation sequence: string_compare}} 
313 do_test collate3-3.2 {
314   catchsql {
315     UPDATE collate3t1 SET c1 = 'xxx';
316   }
317 } {1 {no such collation sequence: string_compare}} 
318 do_test collate3-3.3 {
319   catchsql {
320     UPDATE collate3t1 SET c2 = 'xxx';
321   }
322 } {0 {}}
323 do_test collate3-3.4 {
324   catchsql {
325     DELETE FROM collate3t1 WHERE 1;
326   }
327 } {1 {no such collation sequence: string_compare}} 
328 do_test collate3-3.5 {
329   catchsql {
330     SELECT * FROM collate3t1;
331   }
332 } {0 {xxx xxx}}
333 do_test collate3-3.6 {
334   catchsql {
335     DELETE FROM collate3t1;
336   }
337 } {0 {}}
338 ifcapable {integrityck} {
339   do_test collate3-3.8 {
340     catchsql {
341       PRAGMA integrity_check
342     }
343   } {1 {no such collation sequence: string_compare}}
345 do_test collate3-3.9 {
346   catchsql {
347     SELECT * FROM collate3t1;
348   }
349 } {0 {}}
350 do_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}} 
355 do_test collate3-3.11 {
356   catchsql {
357     SELECT * FROM collate3t1 ORDER BY c1;
358   }
359 } {1 {no such collation sequence: string_compare}} 
360 do_test collate3-3.12 {
361   catchsql {
362     SELECT * FROM collate3t1 WHERE c1 = 'xxx';
363   }
364 } {1 {no such collation sequence: string_compare}} 
365 do_test collate3-3.13 {
366   catchsql {
367     CREATE TABLE collate3t2(c1 COLLATE string_compare);
368   }
369 } {1 {no such collation sequence: string_compare}} 
370 do_test collate3-3.14 {
371   catchsql {
372     CREATE INDEX collate3t1_i2 ON collate3t1(c1);
373   }
374 } {1 {no such collation sequence: string_compare}} 
375 do_test collate3-3.15 {
376   execsql {
377     DROP TABLE collate3t1;
378   }
379 } {}
381 # Check we can create an index that uses an explicit collation 
382 # sequence and then close and re-open the database.
383 do_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 } {}
391 do_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}}
398 do_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 {}}}
404 do_test collate3-4.8.2 {
405   db close
406   lindex [catch {
407     sqlite3 db test.db
408   }] 0
409 } {0}
410 do_test collate3-4.8.3 {
411   execsql {
412     DROP TABLE collate3t1;
413   }
414 } {}
416 # Compare strings as numbers.
417 proc 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
426 # Check we can create a view that uses an explicit collation 
427 # sequence and then close and re-open the database.
428 ifcapable view {
429 do_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 {}}
441 do_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}}
448 do_test collate3-4.11 {
449   db collate user_defined numeric_compare
450   catchsql {
451     SELECT * FROM collate3v1;
452   }
453 } {0 {2 {} 12 {} 101 {}}}
454 do_test collate3-4.12 {
455   execsql {
456     DROP TABLE collate3t1;
457   }
458 } {}
459 } ;# ifcapable view
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.
466 do_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}}
473 do_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 } {}
481 do_test collate3-5.2 {
482   catchsql {
483     SELECT a FROM collate3t1 ORDER BY 1 COLLATE unk;
484   }
485 } {0 10}
486 do_test collate3-5.3 {
487   set ::cfact_cnt
488 } {1}
489 do_test collate3-5.4 {
490   catchsql {
491     SELECT a FROM collate3t1 ORDER BY 1 COLLATE unk;
492   }
493 } {0 10}
494 do_test collate3-5.5 {
495   set ::cfact_cnt
496 } {1}
497 do_test collate3-5.6 {
498   catchsql {
499     SELECT a FROM collate3t1 ORDER BY 1 COLLATE unk;
500   }
501 } {0 10}
502 do_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}}
513 do_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 {}}
525 do_test collate3-5.9 {
526   execsql {
527     DROP TABLE collate3t1;
528   }
529 } {}
531 finish_test