Small performance optimization in sqlite3VdbeRecordCompareWithSkip() for
[sqlite.git] / test / spellfix.test
blob68bcfd5adb1a1b6f2fef7157d9f6fc8e3cbaa832
1 # 2012 July 12
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 #***********************************************************************
13 set testdir [file dirname $argv0]
14 source $testdir/tester.tcl
15 set testprefix spellfix
17 ifcapable !vtab { finish_test ; return }
19 load_static_extension db spellfix nextchar
21 set vocab {
22 rabbi rabbit rabbits rabble rabid rabies raccoon raccoons race raced racer
23 racers races racetrack racial racially racing rack racked racket racketeer
24 racketeering racketeers rackets racking racks radar radars radial radially
25 radian radiance radiant radiantly radiate radiated radiates radiating radiation
26 radiations radiator radiators radical radically radicals radices radii radio
27 radioactive radioastronomy radioed radiography radioing radiology radios radish
28 radishes radium radius radix radon raft rafter rafters rafts rag rage raged
29 rages ragged raggedly raggedness raging rags ragweed raid raided raider raiders
30 raiding raids rail railed railer railers railing railroad railroaded railroader
31 railroaders railroading railroads rails railway railways raiment rain rainbow
32 raincoat raincoats raindrop raindrops rained rainfall rainier rainiest raining
33 rains rainstorm rainy raise raised raiser raisers raises raisin raising rake
34 raked rakes raking rallied rallies rally rallying ram ramble rambler rambles
35 rambling ramblings ramification ramifications ramp rampage rampant rampart
36 ramps ramrod rams ran ranch ranched rancher ranchers ranches ranching rancid
37 random randomization randomize randomized randomizes randomly randomness randy
38 rang range ranged rangeland ranger rangers ranges ranging rangy rank ranked
39 ranker rankers rankest ranking rankings rankle rankly rankness ranks ransack
40 ransacked ransacking ransacks ransom ransomer ransoming ransoms rant ranted
41 ranter ranters ranting rants rap rapacious rape raped raper rapes rapid
42 rapidity rapidly rapids rapier raping rapport rapprochement raps rapt raptly
43 rapture raptures rapturous rare rarely rareness rarer rarest rarity rascal
44 rascally rascals rash rasher rashly rashness rasp raspberry rasped rasping
45 rasps raster rat rate rated rater raters rates rather ratification ratified
46 ratifies ratify ratifying rating ratings ratio ration rational rationale
47 rationales rationalities rationality rationalization rationalizations
48 rationalize rationalized rationalizes rationalizing rationally rationals
49 rationing rations ratios rats rattle rattled rattler rattlers rattles
50 rattlesnake rattlesnakes rattling raucous ravage ravaged ravager ravagers
51 ravages ravaging rave raved raven ravening ravenous ravenously ravens raves
52 ravine ravines raving ravings raw rawer rawest rawly rawness ray rays raze
53 razor razors re reabbreviate reabbreviated reabbreviates reabbreviating reach
54 reachability reachable reachably reached reacher reaches reaching reacquired
55 react reacted reacting reaction reactionaries reactionary reactions reactivate
56 reactivated reactivates reactivating reactivation reactive reactively
57 reactivity reactor reactors reacts read readability readable reader readers
58 readied readier readies readiest readily readiness reading readings readjusted
59 readout readouts reads ready readying real realest realign realigned realigning
60 realigns realism realist realistic realistically realists realities reality
63 do_test 1.1 {
64   execsql { CREATE VIRTUAL TABLE t1 USING spellfix1 }
65   foreach word $vocab {
66     execsql { INSERT INTO t1(word) VALUES($word) }
67   }
68 } {}
70 foreach {tn word res} {
71   1   raxpi*     {rasping 5 rasped 5 ragweed 5 raspberry 6 rasp 4}
72   2   ril*       {rail 4 railed 4 railer 4 railers 4 railing 4}
73   3   rilis*     {realism 6 realist 6 realistic 6 realistically 6 realists 6}
74   4   reail*     {real 3 realest 3 realign 3 realigned 3 realigning 3}
75   5   ras*       {rascal 3 rascally 3 rascals 3 rash 3 rasher 3}
76   6   realistss* {realists 8 realigns 8 realistic 9 realistically 9 realest 7}
77   7   realistss  {realists 8 realist 7 realigns 8 realistic 9 realest 7}
78   8   rllation*  {realities 9 reality 7 rallied 7 railed 4}
79   9   renstom*   {rainstorm 8 ransom 6 ransomer 6 ransoming 6 ransoms 6}
80 } {
81   do_execsql_test 1.2.$tn {
82     SELECT word, matchlen FROM t1 WHERE word MATCH $word 
83      ORDER BY score, word LIMIT 5
84   } $res
87 # Tests of the next_char function.
89 do_test 1.10 {
90   db eval {
91     CREATE TABLE vocab(w TEXT PRIMARY KEY);
92     INSERT INTO vocab SELECT word FROM t1;
93   }
94 } {}
95 do_execsql_test 1.11 {
96   SELECT next_char('re','vocab','w');
97 } {a}
98 do_execsql_test 1.11sub {
99   SELECT next_char('re','(SELECT w AS x FROM vocab)','x');
100 } {a}
101 do_execsql_test 1.12 {
102   SELECT next_char('r','vocab','w');
103 } {ae}
104 do_execsql_test 1.13 {
105   SELECT next_char('','vocab','w');
106 } {r}
107 do_test 1.14 {
108   catchsql {SELECT next_char('','xyzzy','a')}
109 } {1 {no such table: xyzzy}}
111 do_execsql_test 1.20 {
112   CREATE TABLE vocab2(w TEXT);
113   CREATE INDEX vocab2w ON vocab2(w COLLATE nocase);
114   INSERT INTO vocab2 VALUES('abc'), ('ABD'), ('aBe'), ('AbF');
115   SELECT next_char('ab', 'vocab2', 'w', null, 'nocase');
116 } {cDeF}
117 do_execsql_test 1.21 {
118   SELECT next_char('ab','vocab2','w',null,null);
119 } {c}
120 do_execsql_test 1.22 {
121   SELECT next_char('AB','vocab2','w',null,'NOCASE');
122 } {cDeF}
123 do_execsql_test 1.23 {
124   SELECT next_char('ab','vocab2','w',null,'binary');
125 } {c}
127 do_execsql_test 1.30 {
128   SELECT rowid FROM t1 WHERE word='rabbit';
129 } {2}
130 do_execsql_test 1.31 {
131   UPDATE t1 SET rowid=2000 WHERE word='rabbit';
132   SELECT rowid FROM t1 WHERE word='rabbit';
133 } {2000}
134 do_execsql_test 1.32 {
135   INSERT INTO t1(rowid, word) VALUES(3000,'melody');
136   SELECT rowid, word, matchlen FROM t1 WHERE word MATCH 'melotti'
137    ORDER BY score LIMIT 3;
138 } {3000 melody 6}
139 do_test 1.33 {
140   catchsql {INSERT INTO t1(rowid, word) VALUES(3000,'garden');}
141 } {1 {constraint failed}}
143 do_execsql_test 2.1 {
144   CREATE VIRTUAL TABLE t2 USING spellfix1;
145   INSERT INTO t2 (word, soundslike) VALUES('school', 'skuul');
146   INSERT INTO t2 (word, soundslike) VALUES('psalm', 'sarm');
147   SELECT word, matchlen FROM t2 WHERE word MATCH 'sar*' LIMIT 5;
148 } {psalm 4}
150 do_execsql_test 2.2 {
151   SELECT word, matchlen FROM t2 WHERE word MATCH 'skol*' LIMIT 5;
152 } {school 6}
154 set vocab {
155 kangaroo kanji kappa karate keel keeled keeling keels keen keener keenest
156 keenly keenness keep keeper keepers keeping keeps ken kennel kennels kept
157 kerchief kerchiefs kern kernel kernels kerosene ketchup kettle
158 kettles key keyboard keyboards keyed keyhole keying keynote keypad keypads keys
159 keystroke keystrokes keyword keywords kick kicked kicker kickers kicking
160 kickoff kicks kid kidded kiddie kidding kidnap kidnapper kidnappers kidnapping
161 kidnappings kidnaps kidney kidneys kids kill killed killer killers killing
162 killingly killings killjoy kills kilobit kilobits kiloblock kilobyte kilobytes
163 kilogram kilograms kilohertz kilohm kilojoule kilometer kilometers kiloton
164 kilovolt kilowatt kiloword kimono kin kind kinder kindergarten kindest
165 kindhearted kindle kindled kindles kindling kindly kindness kindred kinds
166 kinetic king kingdom kingdoms kingly kingpin kings kink kinky kinship kinsman
167 kiosk kiss kissed kisser kissers kisses kissing kit kitchen kitchenette
168 kitchens kite kited kites kiting kits kitten kittenish kittens kitty klaxon
169 kludge kludges klystron knack knapsack knapsacks knave knaves knead kneads knee
170 kneecap kneed kneeing kneel kneeled kneeling kneels knees knell knells knelt
171 knew knife knifed knifes knifing knight knighted knighthood knighting knightly
172 knights knit knits knives knob knobs knock knockdown knocked knocker knockers
173 knocking knockout knocks knoll knolls knot knots knotted knotting know knowable
174 knower knowhow knowing knowingly knowledge knowledgeable known knows knuckle
175 knuckled knuckles koala kosher kudo
178 do_execsql_test 3.1 {
179   CREATE TABLE costs(iLang, cFrom, cTo, iCost);
180   INSERT INTO costs VALUES(0, 'a', 'e', 1);
181   INSERT INTO costs VALUES(0, 'e', 'i', 1);
182   INSERT INTO costs VALUES(0, 'i', 'o', 1);
183   INSERT INTO costs VALUES(0, 'o', 'u', 1);
184   INSERT INTO costs VALUES(0, 'u', 'a', 1);
185   CREATE VIRTUAL TABLE t3 USING spellfix1(edit_cost_table=costs);
188 do_test 3.2 {
189   foreach w $vocab {
190     execsql { INSERT INTO t3(word) VALUES($w) }
191   }
192 } {}
194 foreach {tn word res} {
195   1   kos*     {kosher 3 kiosk 4 kudo 2 kiss 3 kissed 3}
196   2   kellj*   {killjoy 5 kill 4 killed 4 killer 4 killers 4}
197   3   kellj    {kill 4 kills 5 killjoy 7 keel 4 killed 6}
198 } {
199   do_execsql_test 3.2.$tn {
200     SELECT word, matchlen FROM t3 WHERE word MATCH $word
201      ORDER BY score, word LIMIT 5
202   } $res
205 do_execsql_test 4.0 {
206   INSERT INTO t3(command) VALUES('edit_cost_table=NULL');
208 foreach {tn word res} {
209   1   kosher     {kosher 0 kisser 51 kissers 76 kissed 126 kisses 126}
210   2   kellj      {keels 60 killjoy 68 kills 80 keel 120 kill 125}
211   3   kashar     {kosher 80 kisser 91 kissers 116 kissed 166 kisses 166}
212 } {
213   do_execsql_test 4.1.$tn {
214     SELECT word, distance FROM t3 WHERE word MATCH $word
215      ORDER BY score, word LIMIT 5
216   } $res
218 do_execsql_test 5.0 {
219   CREATE TABLE costs2(iLang, cFrom, cTo, iCost);
220   INSERT INTO costs2 VALUES(0, 'a', 'o', 1);
221   INSERT INTO costs2 VALUES(0, 'e', 'o', 4);
222   INSERT INTO costs2 VALUES(0, 'i', 'o', 8);
223   INSERT INTO costs2 VALUES(0, 'u', 'o', 16);
224   INSERT INTO t3(command) VALUES('edit_cost_table="costs2"');
227 foreach {tn word res} {
228   1   kasher     {kosher 1}
229   2   kesher     {kosher 4}
230   3   kisher     {kosher 8}
231   4   kosher     {kosher 0}
232   5   kusher     {kosher 16}
233 } {
234   do_execsql_test 5.1.$tn {
235     SELECT word, distance FROM t3 WHERE word MATCH $word
236      ORDER BY score, word LIMIT 1
237   } $res
240 #-------------------------------------------------------------------------
241 # Try some queries by rowid.
243 do_execsql_test 6.1.1 {
244   SELECT word FROM t3 WHERE rowid = 10;
245 } {keener}
246 do_execsql_test 6.1.2 {
247   SELECT word, distance FROM t3 WHERE rowid = 10;
248 } {keener {}}
249 do_execsql_test 6.1.3 {
250   SELECT word, distance FROM t3 WHERE rowid = 10 AND word MATCH 'kiiner';
251 } {keener 300}
253 ifcapable trace {
254   proc trace_callback {sql} {
255     if {[string range $sql 0 2] == "-- "} {
256       lappend ::trace [string range $sql 3 end]
257     }
258   }
259   
260   proc do_tracesql_test {tn sql {res {}}} {
261     set ::trace [list]
262     uplevel [list do_test $tn [subst -nocommands {
263       set vals [execsql {$sql}]
264       concat [set vals] [set ::trace]
265     }] [list {*}$res]]
266   }
267   
268   db trace trace_callback
269   do_tracesql_test 6.2.1 {
270     SELECT word FROM t3 WHERE rowid = 10;
271   } {keener
272     {SELECT word, rank, NULL, langid, id FROM "main"."t3_vocab" WHERE rowid=?}
273   }
274   do_tracesql_test 6.2.2 {
275     SELECT word, distance FROM t3 WHERE rowid = 10;
276   } {keener {}
277     {SELECT word, rank, NULL, langid, id FROM "main"."t3_vocab" WHERE rowid=?}
278   }
279   do_tracesql_test 6.2.3 {
280     SELECT word, distance FROM t3 WHERE rowid = 10 AND word MATCH 'kiiner';
281   } {keener 300
282     {SELECT id, word, rank, coalesce(k1,word)  FROM "main"."t3_vocab" WHERE langid=0 AND k2>=?1 AND k2<?2}
283   }
286 #------------------------------------------------------------------------- 
287 # Test that the spellfix1 table supports conflict handling (OR REPLACE 
288 # and so on).
290 do_execsql_test 7.1 {
291   CREATE VIRTUAL TABLE t4 USING spellfix1;
292   PRAGMA table_info = t4;
293 } {
294   0 word {} 0 {} 0 
295   1 rank {} 0 {} 0 
296   2 distance {} 0 {} 0 
297   3 langid {} 0 {} 0 
298   4 score {} 0 {} 0 
299   5 matchlen {} 0 {} 0
302 do_execsql_test 7.2.1 {
303   INSERT INTO t4(rowid, word) VALUES(1, 'Archilles');
304   INSERT INTO t4(rowid, word) VALUES(2, 'Pluto');
305   INSERT INTO t4(rowid, word) VALUES(3, 'Atrides');
306   INSERT OR REPLACE INTO t4(rowid, word) VALUES(2, 'Apollo');
307   SELECT rowid, word FROM t4;
308 } {
309   1 Archilles   2 Apollo   3 Atrides
311 do_catchsql_test 7.2.2 {
312   INSERT OR ABORT INTO t4(rowid, word) VALUES(1, 'Leto');
313 } {1 {constraint failed}}
314 do_catchsql_test 7.2.3 {
315   INSERT OR ROLLBACK INTO t4(rowid, word) VALUES(3, 'Zeus');
316 } {1 {constraint failed}}
317 do_catchsql_test 7.2.4 {
318   INSERT OR FAIL INTO t4(rowid, word) VALUES(3, 'Zeus');
319 } {1 {constraint failed}}
320 do_execsql_test 7.2.5 {
321   INSERT OR IGNORE INTO t4(rowid, word) VALUES(3, 'Zeus');
322   SELECT rowid, word FROM t4;
323 } {
324   1 Archilles   2 Apollo   3 Atrides
327 do_execsql_test 7.3.1 {
328   UPDATE OR REPLACE t4 SET rowid=3 WHERE rowid=1;
329   SELECT rowid, word FROM t4;
330 } {2 Apollo 3 Archilles}
331 do_catchsql_test 7.3.2 {
332   UPDATE OR ABORT t4 SET rowid=3 WHERE rowid=2;
333 } {1 {constraint failed}}
334 do_catchsql_test 7.3.3 {
335   UPDATE OR ROLLBACK t4 SET rowid=3 WHERE rowid=2;
336 } {1 {constraint failed}}
337 do_catchsql_test 7.3.4 {
338   UPDATE OR FAIL t4 SET rowid=3 WHERE rowid=2;
339 } {1 {constraint failed}}
340 do_execsql_test 7.3.5 {
341   UPDATE OR IGNORE t4 SET rowid=3 WHERE rowid=2;
342   SELECT rowid, word FROM t4;
343 } {2 Apollo  3 Archilles}
345 do_execsql_test 7.4.1 {
346   DELETE FROM t4;
347   INSERT INTO t4(rowid, word) VALUES(10, 'Agamemnon');
348   INSERT INTO t4(rowid, word) VALUES(20, 'Patroclus');
349   INSERT INTO t4(rowid, word) VALUES(30, 'Chryses');
351   CREATE TABLE t5(i, w);
352   INSERT INTO t5 VALUES(5,  'Poseidon');
353   INSERT INTO t5 VALUES(20, 'Chronos');
354   INSERT INTO t5 VALUES(30, 'Hera');
357 db_save_and_close
358 foreach {tn conflict err bRollback res} {
359   0 ""            {1 {constraint failed}} 0
360                   {10 Agamemnon 20 Patroclus 30 Chryses}
361   1 "OR REPLACE"  {0 {}} 0
362                   {5 Poseidon 10 Agamemnon 20 Chronos 30 Hera}
363   2 "OR ABORT"    {1 {constraint failed}} 0
364                   {10 Agamemnon 20 Patroclus 30 Chryses}
365   3 "OR ROLLBACK" {1 {constraint failed}} 1
366                   {10 Agamemnon 20 Patroclus 30 Chryses}
367   5 "OR IGNORE"   {0 {}} 0
368                   {5 Poseidon 10 Agamemnon 20 Patroclus 30 Chryses}
369 } {
370   db_restore_and_reopen
371   load_static_extension db spellfix nextchar
373   execsql BEGIN
374   set sql "INSERT $conflict INTO t4(rowid, word) SELECT i, w FROM t5"
375   do_catchsql_test 7.4.2.$tn.1 $sql $err
376   do_execsql_test 7.4.2.$tn.2 { SELECT rowid, word FROM t4 } $res
378   do_test 7.4.2.$tn.3 { sqlite3_get_autocommit db } $bRollback
379   catchsql ROLLBACK
382 foreach {tn conflict err bRollback res} {
383   0 ""            {1 {constraint failed}} 0
384                   {10 Agamemnon 20 Patroclus 30 Chryses}
385   1 "OR REPLACE"  {0 {}} 0
386                   {15 Agamemnon 45 Chryses}
387   2 "OR ABORT"    {1 {constraint failed}} 0
388                   {10 Agamemnon 20 Patroclus 30 Chryses}
389   3 "OR ROLLBACK" {1 {constraint failed}} 1
390                   {10 Agamemnon 20 Patroclus 30 Chryses}
391   5 "OR IGNORE"   {0 {}} 0
392                   {15 Agamemnon 20 Patroclus 45 Chryses}
393 } {
394   db_restore_and_reopen
395   load_static_extension db spellfix nextchar
397   execsql BEGIN
398   set sql "UPDATE $conflict t4 SET rowid=rowid + (rowid/2)"
399   do_catchsql_test 7.5.2.$tn.1 $sql $err
400   do_execsql_test 7.5.2.$tn.2 { SELECT rowid, word FROM t4 } $res
401   do_test 7.5.2.$tn.3 { sqlite3_get_autocommit db } $bRollback
402   catchsql ROLLBACK
405 finish_test