fts5locale.test 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749
  1. # 2014 Dec 20
  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. #
  12. # Tests focusing on the built-in fts5 tokenizers.
  13. #
  14. source [file join [file dirname [info script]] fts5_common.tcl]
  15. set testprefix fts5locale
  16. # If SQLITE_ENABLE_FTS5 is not defined, omit this file.
  17. ifcapable !fts5 {
  18. finish_test
  19. return
  20. }
  21. proc transform_token {locale token} {
  22. switch -- $locale {
  23. reverse {
  24. set ret ""
  25. foreach c [split $token ""] {
  26. set ret "$c$ret"
  27. }
  28. set token $ret
  29. }
  30. default {
  31. # no-op
  32. }
  33. }
  34. set token
  35. }
  36. proc tcl_create {args} { return "tcl_tokenize" }
  37. proc tcl_tokenize {tflags text} {
  38. set iToken 1
  39. set bSkip 0
  40. if {[sqlite3_fts5_locale]=="second"} { set bSkip 1 }
  41. foreach {w iStart iEnd} [fts5_tokenize_split $text] {
  42. incr iToken
  43. if {(($iToken) % ($bSkip + 1))} continue
  44. set w [transform_token [sqlite3_fts5_locale] $w]
  45. sqlite3_fts5_token $w $iStart $iEnd
  46. }
  47. }
  48. #-------------------------------------------------------------------------
  49. # Check that queries can have a locale attached to them.
  50. #
  51. reset_db
  52. sqlite3_fts5_create_tokenizer -v2 db tcl tcl_create
  53. do_execsql_test 1.0 {
  54. CREATE VIRTUAL TABLE t1 USING fts5(a, tokenize=tcl);
  55. INSERT INTO t1 VALUES('abc');
  56. INSERT INTO t1 VALUES('cba');
  57. } {}
  58. do_execsql_test 1.1 {
  59. SELECT rowid, a FROM t1( fts5_locale('en_US', 'abc') );
  60. } {1 abc}
  61. do_execsql_test 1.2 {
  62. SELECT rowid, a FROM t1( fts5_locale('reverse', 'abc') );
  63. } {2 cba}
  64. #-------------------------------------------------------------------------
  65. # Test that the locale= option exists and seems to accept values. And
  66. # that fts5_locale() values may only be inserted into an internal-content
  67. # table if the locale=1 option was specified.
  68. #
  69. reset_db
  70. sqlite3_fts5_create_tokenizer -v2 db tcl tcl_create
  71. do_execsql_test 2.1 {
  72. CREATE VIRTUAL TABLE b1 USING fts5(x, y, locale=1, tokenize=tcl);
  73. CREATE VIRTUAL TABLE b2 USING fts5(x, y, locale=0, tokenize=tcl);
  74. CREATE VIRTUAL TABLE ttt USING fts5vocab('b1', instance);
  75. }
  76. do_catchsql_test 2.2.1 {
  77. CREATE VIRTUAL TABLE b3 USING fts5(x, y, locale=2);
  78. } {1 {malformed locale=... directive}}
  79. do_catchsql_test 2.2.2 {
  80. CREATE VIRTUAL TABLE b3 USING fts5(x, y, locale=111);
  81. } {1 {malformed locale=... directive}}
  82. do_catchsql_test 2.3 {
  83. INSERT INTO b1(b1, rank) VALUES('locale', 0);
  84. } {1 {SQL logic error}}
  85. do_execsql_test 2.4.1 {
  86. INSERT INTO b1 VALUES('abc', 'one two three');
  87. }
  88. do_execsql_test 2.4.2 {
  89. INSERT INTO b1 VALUES('def', fts5_locale('reverse', 'four five six'));
  90. }
  91. do_execsql_test 2.5 {
  92. INSERT INTO b2 VALUES('abc', 'one two three');
  93. }
  94. do_catchsql_test 2.6 {
  95. INSERT INTO b2 VALUES('def', fts5_locale('reverse', 'four five six'));
  96. } {1 {fts5_locale() requires locale=1}}
  97. do_execsql_test 2.7 { SELECT rowid FROM b1('one') } {1}
  98. do_execsql_test 2.8 { SELECT rowid FROM b1('four') } {}
  99. do_execsql_test 2.9 { SELECT rowid FROM b1('ruof') } 2
  100. do_execsql_test 2.10 { SELECT rowid FROM b1(fts5_locale('reverse', 'five'))} 2
  101. do_execsql_test 2.11 {
  102. SELECT x, quote(y) FROM b1
  103. } {
  104. abc {'one two three'}
  105. def {'four five six'}
  106. }
  107. do_execsql_test 2.12 { SELECT quote(y) FROM b1('ruof') } {
  108. {'four five six'}
  109. }
  110. do_execsql_test 2.13 {
  111. INSERT INTO b1(b1) VALUES('integrity-check');
  112. }
  113. do_execsql_test 2.14 {
  114. INSERT INTO b1(b1) VALUES('rebuild');
  115. }
  116. do_execsql_test 2.15 {
  117. INSERT INTO b1(b1) VALUES('integrity-check');
  118. }
  119. do_execsql_test 2.16 {
  120. DELETE FROM b1 WHERE rowid=2
  121. }
  122. do_execsql_test 2.17 {
  123. INSERT INTO b1(b1) VALUES('integrity-check');
  124. }
  125. do_execsql_test 2.18 {
  126. INSERT INTO b1(rowid, x, y) VALUES(
  127. test_setsubtype(45, 76), 'abc def', 'def abc'
  128. );
  129. }
  130. #-------------------------------------------------------------------------
  131. # Test the 'delete' command with contentless tables.
  132. #
  133. reset_db
  134. sqlite3_fts5_create_tokenizer -v2 db tcl tcl_create
  135. do_execsql_test 3.1 {
  136. CREATE VIRTUAL TABLE c1 USING fts5(x, content=, tokenize=tcl, locale=1);
  137. CREATE VIRTUAL TABLE c2 USING fts5vocab('c1', instance);
  138. INSERT INTO c1 VALUES('hello world');
  139. INSERT INTO c1 VALUES( fts5_locale('reverse', 'one two three') );
  140. }
  141. do_execsql_test 3.2 {
  142. SELECT DISTINCT term FROM c2 ORDER BY 1
  143. } {
  144. eerht eno hello owt world
  145. }
  146. do_execsql_test 3.3 {
  147. INSERT INTO c1(c1, rowid, x)
  148. VALUES('delete', 2, fts5_locale('reverse', 'one two three') );
  149. }
  150. do_execsql_test 3.4 {
  151. SELECT DISTINCT term FROM c2 ORDER BY 1
  152. } {
  153. hello world
  154. }
  155. #-------------------------------------------------------------------------
  156. # Test that an UPDATE that updates a subset of the columns does not
  157. # magically discard the locale from those columns not updated.
  158. #
  159. reset_db
  160. sqlite3_fts5_create_tokenizer -v2 db tcl tcl_create
  161. do_execsql_test 4.1 {
  162. CREATE VIRTUAL TABLE d1 USING fts5(x, y, locale=1, tokenize=tcl);
  163. CREATE VIRTUAL TABLE d2 USING fts5vocab('d1', instance);
  164. INSERT INTO d1(rowid, x, y) VALUES(1, 'abc', 'def');
  165. INSERT INTO d1(rowid, x, y) VALUES(2, 'ghi', fts5_locale('reverse', 'hello'));
  166. }
  167. do_execsql_test 4.2 {
  168. SELECT DISTINCT term FROM d2 ORDER BY 1
  169. } {
  170. abc def ghi olleh
  171. }
  172. do_execsql_test 4.3 {
  173. UPDATE d1 SET x='jkl' WHERE rowid=2;
  174. }
  175. do_execsql_test 4.4 {
  176. SELECT DISTINCT term FROM d2 ORDER BY 1
  177. } {
  178. abc def jkl olleh
  179. }
  180. do_execsql_test 4.5 {
  181. SELECT rowid, * FROM d1
  182. } {
  183. 1 abc def
  184. 2 jkl hello
  185. }
  186. do_execsql_test 4.6 {
  187. UPDATE d1 SET rowid=4 WHERE rowid=2
  188. }
  189. do_execsql_test 4.7 {
  190. SELECT rowid, * FROM d1
  191. } {
  192. 1 abc def
  193. 4 jkl hello
  194. }
  195. fts5_aux_test_functions db
  196. do_execsql_test 4.8.1 {
  197. SELECT fts5_test_columntext(d1) FROM d1('jkl')
  198. } {{jkl hello}}
  199. do_execsql_test 4.8.2 {
  200. SELECT fts5_test_columntext(d1) FROM d1(fts5_locale('reverse', 'hello'))
  201. } {{jkl hello}}
  202. do_execsql_test 4.9 {
  203. SELECT fts5_test_columnlocale(d1) FROM d1(fts5_locale('reverse', 'hello'))
  204. } {{{} reverse}}
  205. do_execsql_test 4.10 {
  206. SELECT fts5_test_columnlocale(d1) FROM d1
  207. } {
  208. {{} {}}
  209. {{} reverse}
  210. }
  211. #-------------------------------------------------------------------------
  212. # Test that if an fts5_locale() value is written to an UNINDEXED
  213. # column it is stored as text. This is so that blobs and other values
  214. # can also be stored as is.
  215. #
  216. reset_db
  217. sqlite3_fts5_create_tokenizer -v2 db tcl tcl_create
  218. do_execsql_test 5.1 {
  219. CREATE VIRTUAL TABLE t1 USING fts5(
  220. x, y UNINDEXED, locale=1, tokenize=tcl
  221. );
  222. INSERT INTO t1(rowid, x, y) VALUES(111,
  223. fts5_locale('reverse', 'one two three'),
  224. fts5_locale('reverse', 'four five six')
  225. );
  226. }
  227. do_execsql_test 5.2 {
  228. SELECT rowid, x, y FROM t1
  229. } {
  230. 111 {one two three} {four five six}
  231. }
  232. do_execsql_test 5.3 {
  233. SELECT typeof(c0), typeof(c1), typeof(l0) FROM t1_content
  234. } {
  235. text text text
  236. }
  237. #-------------------------------------------------------------------------
  238. foreach {tn opt} {
  239. 1 {}
  240. 2 {, columnsize=0}
  241. } {
  242. reset_db
  243. sqlite3_fts5_create_tokenizer -v2 db tcl tcl_create
  244. do_execsql_test 6.$tn.1 "
  245. CREATE VIRTUAL TABLE y1 USING fts5(t, locale=1, tokenize=tcl $opt);
  246. "
  247. do_execsql_test 6.$tn.2 {
  248. INSERT INTO y1(rowid, t) VALUES
  249. (1, fts5_locale('second', 'the city of London')),
  250. (2, fts5_locale('second', 'shall have all the old')),
  251. (3, fts5_locale('second', 'Liberties and Customs')),
  252. (4, fts5_locale('second', 'which it hath been used to have'));
  253. }
  254. fts5_aux_test_functions db
  255. do_execsql_test 6.$tn.3 {
  256. SELECT fts5_test_columnsize(y1) FROM y1
  257. } {
  258. 2 3 2 4
  259. }
  260. do_execsql_test 6.$tn.4 {
  261. SELECT rowid, fts5_test_columnsize(y1) FROM y1('shall');
  262. } {
  263. 2 3
  264. }
  265. do_execsql_test 6.$tn.5 {
  266. SELECT rowid, fts5_test_columnsize(y1) FROM y1('shall');
  267. } {
  268. 2 3
  269. }
  270. do_execsql_test 6.$tn.6 {
  271. SELECT rowid, fts5_test_columnsize(y1) FROM y1('have');
  272. } {
  273. 4 4
  274. }
  275. do_execsql_test 6.$tn.7 {
  276. SELECT rowid, highlight(y1, 0, '[', ']') FROM y1('have');
  277. } {
  278. 4 {which it hath been used to [have]}
  279. }
  280. do_execsql_test 6.$tn.8 {
  281. SELECT rowid,
  282. highlight(y1, 0, '[', ']'),
  283. snippet(y1, 0, '[', ']', '...', 10)
  284. FROM y1('Liberties + Customs');
  285. } {
  286. 3 {[Liberties and Customs]}
  287. {[Liberties and Customs]}
  288. }
  289. }
  290. #-------------------------------------------------------------------------
  291. reset_db
  292. do_execsql_test 6.0 {
  293. CREATE VIRTUAL TABLE x1 USING fts5(x);
  294. }
  295. do_catchsql_test 6.1 {
  296. INSERT INTO x1(rowid, x) VALUES(123, fts5_locale('en_AU', 'hello world'));
  297. } {1 {fts5_locale() requires locale=1}}
  298. do_execsql_test 6.2 {
  299. SELECT typeof( fts5_locale(NULL, 'xyz') ), typeof( fts5_locale('', 'abc') );
  300. } {text text}
  301. #--------------------------------------------------------------------------
  302. # Test that fts5_locale() works with external-content tables.
  303. #
  304. reset_db
  305. sqlite3_fts5_create_tokenizer -v2 db tcl tcl_create
  306. do_execsql_test 7.1 {
  307. CREATE TABLE t1(ii INTEGER PRIMARY KEY, bb BLOB, tt TEXT, locale TEXT);
  308. CREATE VIEW v1 AS
  309. SELECT ii AS rowid, bb, fts5_locale(locale, tt) AS tt FROM t1;
  310. CREATE VIRTUAL TABLE ft USING fts5(
  311. bb, tt, locale=1, tokenize=tcl, content=v1
  312. );
  313. INSERT INTO t1 VALUES(1, NULL, 'one two three', NULL);
  314. INSERT INTO t1 VALUES(2, '7800616263', 'four five six', 'reverse');
  315. INSERT INTO t1 VALUES(3, '000000007800616263', 'seven eight nine', 'second');
  316. }
  317. do_execsql_test 7.2 {
  318. INSERT INTO ft(ft) VALUES('rebuild');
  319. INSERT INTO ft(ft) VALUES('integrity-check');
  320. }
  321. do_execsql_test 7.3 {
  322. SELECT rowid, quote(bb), quote(tt) FROM ft
  323. } {
  324. 1 NULL {'one two three'}
  325. 2 '7800616263' {'four five six'}
  326. 3 '000000007800616263' {'seven eight nine'}
  327. }
  328. do_execsql_test 7.4 { SELECT rowid FROM ft('six'); }
  329. do_execsql_test 7.5 { SELECT rowid FROM ft(fts5_locale('reverse','six')); } 2
  330. fts5_aux_test_functions db
  331. do_execsql_test 7.6 {
  332. SELECT fts5_test_columnlocale(ft) FROM ft;
  333. } {
  334. {{} {}} {{} reverse} {{} second}
  335. }
  336. #-------------------------------------------------------------------------
  337. # Test that the porter tokenizer works with locales.
  338. #
  339. reset_db
  340. sqlite3_fts5_create_tokenizer -v2 db tcl tcl_create
  341. do_execsql_test 8.1 {
  342. CREATE VIRTUAL TABLE ft USING fts5(tt, locale=1, tokenize="porter tcl");
  343. CREATE VIRTUAL TABLE vocab USING fts5vocab('ft', instance);
  344. INSERT INTO ft(rowid, tt) VALUES
  345. (111, fts5_locale('second', 'the porter tokenizer is a wrapper tokenizer')),
  346. (222, fts5_locale('reverse', 'This value may also be set'));
  347. }
  348. do_execsql_test 8.1 {
  349. SELECT DISTINCT term FROM vocab ORDER BY 1
  350. } {
  351. a eb eulav osla sihT te the token yam
  352. }
  353. #-------------------------------------------------------------------------
  354. # Test that position-lists (used by xInst, xPhraseFirst etc.) work with
  355. # locales and modes other than detail=full.
  356. #
  357. foreach {tn detail} {
  358. 1 detail=full
  359. 2 detail=none
  360. 3 detail=column
  361. } {
  362. reset_db
  363. sqlite3_fts5_create_tokenizer -v2 db tcl tcl_create
  364. do_execsql_test 9.$tn.0 "
  365. CREATE VIRTUAL TABLE ft USING fts5(tt, locale=1, tokenize=tcl, $detail);
  366. "
  367. do_execsql_test 9.$tn.1 {
  368. CREATE VIRTUAL TABLE vocab USING fts5vocab('ft', instance);
  369. INSERT INTO ft(rowid, tt) VALUES
  370. (-1, fts5_locale('second', 'it is an ancient mariner'));
  371. }
  372. do_execsql_test 9.$tn.2 {
  373. SELECT DISTINCT term FROM vocab
  374. } {an it mariner}
  375. do_execsql_test 9.$tn.3 {
  376. SELECT highlight(ft, 0, '[', ']') FROM ft('mariner')
  377. } {{it is an ancient [mariner]}}
  378. }
  379. #-------------------------------------------------------------------------
  380. # Check some corrupt fts5_locale() blob formats are detected.
  381. #
  382. foreach_detail_mode $::testprefix {
  383. reset_db
  384. sqlite3_fts5_create_tokenizer -v2 db tcl tcl_create
  385. fts5_aux_test_functions db
  386. do_execsql_test 10.1 {
  387. CREATE TABLE x1(ii INTEGER PRIMARY KEY, x);
  388. CREATE VIRTUAL TABLE ft USING fts5(x,
  389. content=x1, content_rowid=ii, locale=1, detail=%DETAIL%, columnsize=0
  390. );
  391. CREATE VIRTUAL TABLE ft2 USING fts5(
  392. x, locale=1, detail=%DETAIL%, columnsize=0
  393. );
  394. }
  395. foreach {tn v} {
  396. 1 X'001152'
  397. 2 X'0011223344'
  398. 3 X'00E0B2EB68656c6c6f'
  399. 4 X'00E0B2EB0068656c6c6f'
  400. } {
  401. do_execsql_test 10.2.$tn.0 { INSERT INTO ft(ft) VALUES('delete-all') }
  402. do_execsql_test 10.2.$tn.1 { DELETE FROM x1; }
  403. do_execsql_test 10.2.$tn.2 " INSERT INTO x1 VALUES(NULL, $v) "
  404. do_catchsql_test 10.2.$tn.3 {
  405. INSERT INTO ft(ft) VALUES('rebuild');
  406. } {0 {}}
  407. do_catchsql_test 10.2.$tn.4 "
  408. SELECT * FROM ft( test_setsubtype($v, 76) );
  409. " {1 {fts5: syntax error near ""}}
  410. do_execsql_test 10.2.$tn.5 {
  411. INSERT INTO ft(rowid, x) VALUES(1, 'hello world');
  412. }
  413. if {"%DETAIL%"=="full"} {
  414. do_execsql_test 10.2.$tn.6 {
  415. SELECT fts5_test_poslist(ft) FROM ft('world');
  416. } {0.0.1}
  417. do_execsql_test 10.2.$tn.7.1 {
  418. SELECT fts5_test_columnsize(ft) FROM ft('world');
  419. } {1}
  420. do_execsql_test 10.2.$tn.7.2 {
  421. SELECT fts5_test_columnlocale(ft) FROM ft('world');
  422. } {{{}}}
  423. }
  424. do_catchsql_test 10.2.$tn.8 {
  425. SELECT count(*) FROM ft('hello')
  426. } {0 1}
  427. do_catchsql_test 10.2.$tn.9 {
  428. PRAGMA integrity_check;
  429. } {0 ok}
  430. do_execsql_test 10.2.$tn.10 {
  431. DELETE FROM x1;
  432. INSERT INTO x1(ii, x) VALUES(1, 'hello world');
  433. }
  434. do_catchsql_test 10.2.$tn.11 "
  435. INSERT INTO ft(ft, rowid, x) VALUES('delete', 1, test_setsubtype($v,76) )
  436. " {0 {}}
  437. do_catchsql_test 10.2.$tn.12 "
  438. INSERT INTO ft(rowid, x) VALUES(2, test_setsubtype($v,76) )
  439. " {0 {}}
  440. do_execsql_test 10.2.$tn.13 {
  441. INSERT INTO ft2(rowid, x) VALUES(1, 'hello world');
  442. }
  443. do_execsql_test 10.2.$tn.14 "UPDATE ft2_content SET c0=$v"
  444. do_catchsql_test 10.2.$tn.15 {
  445. PRAGMA integrity_check;
  446. } {0 {{malformed inverted index for FTS5 table main.ft2}}}
  447. do_execsql_test 10.2.$tn.16 {
  448. DELETE FROM ft2_content;
  449. INSERT INTO ft2(ft2) VALUES('rebuild');
  450. }
  451. }
  452. }
  453. #-------------------------------------------------------------------------
  454. #
  455. reset_db
  456. sqlite3_fts5_create_tokenizer -v2 db tcl tcl_create
  457. fts5_aux_test_functions db
  458. do_execsql_test 11.0 {
  459. CREATE VIRTUAL TABLE x1 USING fts5(abc, locale=1);
  460. INSERT INTO x1(rowid, abc) VALUES(123, fts5_locale('en_US', 'one two three'));
  461. }
  462. do_catchsql_test 11.1 {
  463. SELECT fts5_columnlocale(x1, -1) FROM x1('two');
  464. } {1 SQLITE_RANGE}
  465. do_catchsql_test 11.2 {
  466. SELECT fts5_columnlocale(x1, 1) FROM x1('two');
  467. } {1 SQLITE_RANGE}
  468. #-------------------------------------------------------------------------
  469. #
  470. reset_db
  471. do_test 12.0 {
  472. list [catch {
  473. sqlite3_fts5_create_tokenizer -v2 -version 3 db tcl tcl_create
  474. } msg] $msg
  475. } {1 {error in fts5_api.xCreateTokenizer_v2()}}
  476. #-------------------------------------------------------------------------
  477. # Tests for auxiliary function fts5_get_locale().
  478. #
  479. reset_db
  480. # Check that if the table does not support locale=1, fts5_get_locale()
  481. # always returns NULL.
  482. do_execsql_test 13.1.0 {
  483. CREATE VIRTUAL TABLE nolocale USING fts5(a, b);
  484. INSERT INTO nolocale VALUES('one two three', 'four five six');
  485. INSERT INTO nolocale VALUES('three two one', 'seven eight nine');
  486. }
  487. do_execsql_test 13.1.1 {
  488. SELECT fts5_get_locale(nolocale, 0) IS NULL FROM nolocale;
  489. } {1 1}
  490. do_execsql_test 13.1.2 {
  491. SELECT fts5_get_locale(nolocale, 1) IS NULL FROM nolocale('one + two');
  492. } {1}
  493. do_execsql_test 13.1.3 {
  494. SELECT fts5_get_locale(nolocale, 0) IS NULL FROM nolocale('one AND two');
  495. } {1 1}
  496. do_execsql_test 13.1.4 {
  497. SELECT
  498. fts5_get_locale(nolocale, 1) IS NULL
  499. FROM nolocale('three AND two') ORDER BY rank
  500. } {1 1}
  501. do_catchsql_test 13.1.5 {
  502. SELECT fts5_get_locale(nolocale, 2) IS NULL FROM nolocale('three AND two');
  503. } {1 {column index out of range}}
  504. do_catchsql_test 13.1.6 {
  505. SELECT fts5_get_locale(nolocale, -1) IS NULL FROM nolocale('three AND two');
  506. } {1 {column index out of range}}
  507. do_catchsql_test 13.1.7 {
  508. SELECT fts5_get_locale(nolocale) IS NULL FROM nolocale('three AND two');
  509. } {1 {wrong number of arguments to function fts5_get_locale()}}
  510. do_catchsql_test 13.1.8 {
  511. SELECT fts5_get_locale(nolocale, 0, 0) IS NULL FROM nolocale('three AND two');
  512. } {1 {wrong number of arguments to function fts5_get_locale()}}
  513. do_catchsql_test 13.1.9 {
  514. SELECT fts5_get_locale(nolocale, 'text') FROM nolocale('three AND two');
  515. } {1 {non-integer argument passed to function fts5_get_locale()}}
  516. # Check that if the table does support locale=1, fts5_get_locale()
  517. # returns the locale of the identified row/column.
  518. do_execsql_test 13.2.0 {
  519. CREATE VIRTUAL TABLE ft USING fts5(a, b, locale=1);
  520. INSERT INTO ft VALUES(
  521. fts5_locale('th_TH', 'one two three'), 'four five six seven'
  522. );
  523. INSERT INTO ft VALUES(
  524. 'three two one', fts5_locale('en_AU', 'seven eight nine')
  525. );
  526. }
  527. do_execsql_test 13.2.1 {
  528. SELECT quote(fts5_get_locale(ft, 0)), quote(fts5_get_locale(ft, 1)) FROM ft
  529. } { 'th_TH' NULL NULL 'en_AU' }
  530. do_execsql_test 13.2.2 {
  531. SELECT
  532. quote(fts5_get_locale(ft, 0)), quote(fts5_get_locale(ft, 1))
  533. FROM ft('one AND three')
  534. } { 'th_TH' NULL NULL 'en_AU' }
  535. do_execsql_test 13.2.3 {
  536. SELECT
  537. quote(fts5_get_locale(ft, 0)), quote(fts5_get_locale(ft, 1))
  538. FROM ft('one AND three') ORDER BY rank
  539. } { NULL 'en_AU' 'th_TH' NULL }
  540. do_execsql_test 13.2.4 {
  541. SELECT
  542. quote(fts5_get_locale(ft, 0)), quote(fts5_get_locale(ft, 1))
  543. FROM ft('one AND three') ORDER BY rowid
  544. } { 'th_TH' NULL NULL 'en_AU' }
  545. do_execsql_test 13.2.5 {
  546. SELECT
  547. quote(fts5_get_locale(ft, '0')), quote(fts5_get_locale(ft, 1))
  548. FROM ft('one AND three') ORDER BY rowid
  549. } { 'th_TH' NULL NULL 'en_AU' }
  550. do_catchsql_test 13.2.6 {
  551. SELECT
  552. quote(fts5_get_locale(ft, '0.0')), quote(fts5_get_locale(ft, 1))
  553. FROM ft('one AND three') ORDER BY rowid
  554. } {1 {non-integer argument passed to function fts5_get_locale()}}
  555. do_catchsql_test 13.2.7 {
  556. SELECT
  557. quote(fts5_get_locale(ft, 0.0)), quote(fts5_get_locale(ft, 1))
  558. FROM ft('one AND three') ORDER BY rowid
  559. } {1 {non-integer argument passed to function fts5_get_locale()}}
  560. #-------------------------------------------------------------------------
  561. # Check that UPDATE statements that may affect more than one row work.
  562. #
  563. reset_db
  564. do_execsql_test 14.1 {
  565. CREATE VIRTUAL TABLE ft USING fts5(a, b, locale=1);
  566. }
  567. do_execsql_test 14.2 {
  568. INSERT INTO ft VALUES('hello', 'world');
  569. }
  570. do_execsql_test 14.3 {
  571. UPDATE ft SET b = fts5_locale('en_AU', 'world');
  572. }
  573. do_execsql_test 14.4 {
  574. INSERT INTO ft VALUES(X'abcd', X'1234');
  575. } {}
  576. do_execsql_test 14.5 {
  577. SELECT quote(a), quote(b) FROM ft
  578. } {'hello' 'world' X'ABCD' X'1234'}
  579. do_execsql_test 14.6 {
  580. DELETE FROM ft;
  581. INSERT INTO ft VALUES(NULL, 'null');
  582. INSERT INTO ft VALUES(123, 'int');
  583. INSERT INTO ft VALUES(345.0, 'real');
  584. INSERT INTO ft VALUES('abc', 'text');
  585. INSERT INTO ft VALUES(fts5_locale('abc', 'def'), 'text');
  586. SELECT a, typeof(a), b FROM ft
  587. } {
  588. {} null null
  589. 123 integer int
  590. 345.0 real real
  591. abc text text
  592. def text text
  593. }
  594. do_execsql_test 14.7 {
  595. SELECT quote(c0), typeof(c0) FROM ft_content
  596. } {
  597. NULL null
  598. 123 integer
  599. 345.0 real
  600. 'abc' text
  601. 'def' text
  602. }
  603. #-------------------------------------------------------------------------
  604. # Check that inserting UNINDEXED columns between indexed columns of a
  605. # locale=1 table does not cause a problem.
  606. #
  607. reset_db
  608. sqlite3_fts5_create_tokenizer -v2 db tcl tcl_create
  609. fts5_aux_test_functions db
  610. do_execsql_test 15.1 {
  611. CREATE VIRTUAL TABLE ft USING fts5(a, b UNINDEXED, c, locale=1, tokenize=tcl);
  612. }
  613. do_execsql_test 15.2 {
  614. INSERT INTO ft VALUES('one', 'two', 'three');
  615. INSERT INTO ft VALUES('one', 'two', fts5_locale('loc', 'three'));
  616. }
  617. do_execsql_test 15.3 {
  618. SELECT c2, l2 FROM ft_content
  619. } {three {} three loc}
  620. do_execsql_test 15.4 {
  621. SELECT c, fts5_columnlocale(ft, 2) FROM ft
  622. } {three {} three loc}
  623. finish_test