mirror of
https://github.com/sqlite/sqlite.git
synced 2026-01-06 08:01:16 +03:00
Add the "^" syntax from fts3/4 to fts5.
FossilOrigin-Name: 24d7058e2799133dd681d2fef341025ca50554861bb4cd39e93ee87ae1d8a605
This commit is contained in:
@@ -722,6 +722,8 @@ Fts5ExprPhrase *sqlite3Fts5ParseTerm(
|
||||
int bPrefix
|
||||
);
|
||||
|
||||
void sqlite3Fts5ParseSetCaret(Fts5ExprPhrase*);
|
||||
|
||||
Fts5ExprNearset *sqlite3Fts5ParseNearset(
|
||||
Fts5Parse*,
|
||||
Fts5ExprNearset*,
|
||||
|
||||
@@ -87,7 +87,8 @@ struct Fts5ExprNode {
|
||||
** or term prefix.
|
||||
*/
|
||||
struct Fts5ExprTerm {
|
||||
int bPrefix; /* True for a prefix term */
|
||||
u8 bPrefix; /* True for a prefix term */
|
||||
u8 bFirst; /* True if token must be first in column */
|
||||
char *zTerm; /* nul-terminated term */
|
||||
Fts5IndexIter *pIter; /* Iterator for this term */
|
||||
Fts5ExprTerm *pSynonym; /* Pointer to first in list of synonyms */
|
||||
@@ -168,6 +169,7 @@ static int fts5ExprGetToken(
|
||||
case '+': tok = FTS5_PLUS; break;
|
||||
case '*': tok = FTS5_STAR; break;
|
||||
case '-': tok = FTS5_MINUS; break;
|
||||
case '^': tok = FTS5_CARET; break;
|
||||
case '\0': tok = FTS5_EOF; break;
|
||||
|
||||
case '"': {
|
||||
@@ -427,6 +429,7 @@ static int fts5ExprPhraseIsMatch(
|
||||
Fts5PoslistReader *aIter = aStatic;
|
||||
int i;
|
||||
int rc = SQLITE_OK;
|
||||
int bFirst = pPhrase->aTerm[0].bFirst;
|
||||
|
||||
fts5BufferZero(&pPhrase->poslist);
|
||||
|
||||
@@ -481,8 +484,10 @@ static int fts5ExprPhraseIsMatch(
|
||||
}while( bMatch==0 );
|
||||
|
||||
/* Append position iPos to the output */
|
||||
rc = sqlite3Fts5PoslistWriterAppend(&pPhrase->poslist, &writer, iPos);
|
||||
if( rc!=SQLITE_OK ) goto ismatch_out;
|
||||
if( bFirst==0 || FTS5_POS2OFFSET(iPos)==0 ){
|
||||
rc = sqlite3Fts5PoslistWriterAppend(&pPhrase->poslist, &writer, iPos);
|
||||
if( rc!=SQLITE_OK ) goto ismatch_out;
|
||||
}
|
||||
|
||||
for(i=0; i<pPhrase->nTerm; i++){
|
||||
if( sqlite3Fts5PoslistReaderNext(&aIter[i]) ) goto ismatch_out;
|
||||
@@ -736,7 +741,9 @@ static int fts5ExprNearTest(
|
||||
** phrase is not a match, break out of the loop early. */
|
||||
for(i=0; rc==SQLITE_OK && i<pNear->nPhrase; i++){
|
||||
Fts5ExprPhrase *pPhrase = pNear->apPhrase[i];
|
||||
if( pPhrase->nTerm>1 || pPhrase->aTerm[0].pSynonym || pNear->pColset ){
|
||||
if( pPhrase->nTerm>1 || pPhrase->aTerm[0].pSynonym
|
||||
|| pNear->pColset || pPhrase->aTerm[0].bFirst
|
||||
){
|
||||
int bMatch = 0;
|
||||
rc = fts5ExprPhraseIsMatch(pNode, pPhrase, &bMatch);
|
||||
if( bMatch==0 ) break;
|
||||
@@ -917,6 +924,7 @@ static int fts5ExprNodeTest_STRING(
|
||||
assert( pNear->nPhrase>1
|
||||
|| pNear->apPhrase[0]->nTerm>1
|
||||
|| pNear->apPhrase[0]->aTerm[0].pSynonym
|
||||
|| pNear->apPhrase[0]->aTerm[0].bFirst
|
||||
);
|
||||
|
||||
/* Initialize iLast, the "lastest" rowid any iterator points to. If the
|
||||
@@ -1441,6 +1449,16 @@ static void fts5ExprPhraseFree(Fts5ExprPhrase *pPhrase){
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Set the "bFirst" flag on the first token of the phrase passed as the
|
||||
** only argument.
|
||||
*/
|
||||
void sqlite3Fts5ParseSetCaret(Fts5ExprPhrase *pPhrase){
|
||||
if( pPhrase && pPhrase->nTerm ){
|
||||
pPhrase->aTerm[0].bFirst = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** If argument pNear is NULL, then a new Fts5ExprNearset object is allocated
|
||||
** and populated with pPhrase. Or, if pNear is not NULL, phrase pPhrase is
|
||||
@@ -1719,6 +1737,7 @@ int sqlite3Fts5ExprClonePhrase(
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
sCtx.pPhrase->aTerm[i].bPrefix = pOrig->aTerm[i].bPrefix;
|
||||
sCtx.pPhrase->aTerm[i].bFirst = pOrig->aTerm[i].bFirst;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
@@ -1737,7 +1756,10 @@ int sqlite3Fts5ExprClonePhrase(
|
||||
pNew->pRoot->pNear->nPhrase = 1;
|
||||
sCtx.pPhrase->pNode = pNew->pRoot;
|
||||
|
||||
if( pOrig->nTerm==1 && pOrig->aTerm[0].pSynonym==0 ){
|
||||
if( pOrig->nTerm==1
|
||||
&& pOrig->aTerm[0].pSynonym==0
|
||||
&& pOrig->aTerm[0].bFirst==0
|
||||
){
|
||||
pNew->pRoot->eType = FTS5_TERM;
|
||||
pNew->pRoot->xNext = fts5ExprNodeNext_TERM;
|
||||
}else{
|
||||
@@ -2011,6 +2033,7 @@ static void fts5ExprAssignXNext(Fts5ExprNode *pNode){
|
||||
Fts5ExprNearset *pNear = pNode->pNear;
|
||||
if( pNear->nPhrase==1 && pNear->apPhrase[0]->nTerm==1
|
||||
&& pNear->apPhrase[0]->aTerm[0].pSynonym==0
|
||||
&& pNear->apPhrase[0]->aTerm[0].bFirst==0
|
||||
){
|
||||
pNode->eType = FTS5_TERM;
|
||||
pNode->xNext = fts5ExprNodeNext_TERM;
|
||||
@@ -2097,20 +2120,23 @@ Fts5ExprNode *sqlite3Fts5ParseNode(
|
||||
}
|
||||
}
|
||||
|
||||
if( pParse->pConfig->eDetail!=FTS5_DETAIL_FULL
|
||||
&& (pNear->nPhrase!=1 || pNear->apPhrase[0]->nTerm>1)
|
||||
){
|
||||
assert( pParse->rc==SQLITE_OK );
|
||||
pParse->rc = SQLITE_ERROR;
|
||||
assert( pParse->zErr==0 );
|
||||
pParse->zErr = sqlite3_mprintf(
|
||||
"fts5: %s queries are not supported (detail!=full)",
|
||||
pNear->nPhrase==1 ? "phrase": "NEAR"
|
||||
);
|
||||
sqlite3_free(pRet);
|
||||
pRet = 0;
|
||||
if( pParse->pConfig->eDetail!=FTS5_DETAIL_FULL ){
|
||||
Fts5ExprPhrase *pPhrase = pNear->apPhrase[0];
|
||||
if( pNear->nPhrase!=1
|
||||
|| pPhrase->nTerm>1
|
||||
|| (pPhrase->nTerm>0 && pPhrase->aTerm[0].bFirst)
|
||||
){
|
||||
assert( pParse->rc==SQLITE_OK );
|
||||
pParse->rc = SQLITE_ERROR;
|
||||
assert( pParse->zErr==0 );
|
||||
pParse->zErr = sqlite3_mprintf(
|
||||
"fts5: %s queries are not supported (detail!=full)",
|
||||
pNear->nPhrase==1 ? "phrase": "NEAR"
|
||||
);
|
||||
sqlite3_free(pRet);
|
||||
pRet = 0;
|
||||
}
|
||||
}
|
||||
|
||||
}else{
|
||||
fts5ExprAddChildren(pRet, pLeft);
|
||||
fts5ExprAddChildren(pRet, pRight);
|
||||
|
||||
@@ -148,7 +148,11 @@ cnearset(A) ::= colset(X) COLON nearset(Y). {
|
||||
%destructor nearset { sqlite3Fts5ParseNearsetFree($$); }
|
||||
%destructor nearphrases { sqlite3Fts5ParseNearsetFree($$); }
|
||||
|
||||
nearset(A) ::= phrase(X). { A = sqlite3Fts5ParseNearset(pParse, 0, X); }
|
||||
nearset(A) ::= phrase(Y). { A = sqlite3Fts5ParseNearset(pParse, 0, Y); }
|
||||
nearset(A) ::= CARET phrase(Y). {
|
||||
sqlite3Fts5ParseSetCaret(Y);
|
||||
A = sqlite3Fts5ParseNearset(pParse, 0, Y);
|
||||
}
|
||||
nearset(A) ::= STRING(X) LP nearphrases(Y) neardist_opt(Z) RP. {
|
||||
sqlite3Fts5ParseNear(pParse, &X);
|
||||
sqlite3Fts5ParseSetDistance(pParse, Y, &Z);
|
||||
@@ -189,6 +193,5 @@ phrase(A) ::= STRING(Y) star_opt(Z). {
|
||||
** Optional "*" character.
|
||||
*/
|
||||
%type star_opt {int}
|
||||
|
||||
star_opt(A) ::= STAR. { A = 1; }
|
||||
star_opt(A) ::= . { A = 0; }
|
||||
|
||||
@@ -130,5 +130,22 @@ do_faultsim_test 4.2 -faults oom* -body {
|
||||
faultsim_test_result {0 {2 3}}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test OOM injection while parsing a CARET expression
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 5.0 {
|
||||
CREATE VIRTUAL TABLE t1 USING fts5(a);
|
||||
INSERT INTO t1 VALUES('a b c d'); -- 1
|
||||
INSERT INTO t1 VALUES('d a b c'); -- 2
|
||||
INSERT INTO t1 VALUES('c d a b'); -- 3
|
||||
INSERT INTO t1 VALUES('b c d a'); -- 4
|
||||
}
|
||||
do_faultsim_test 5.1 -faults oom* -body {
|
||||
execsql { SELECT rowid FROM t1('^a OR ^b') }
|
||||
} -test {
|
||||
faultsim_test_result {0 {1 4}}
|
||||
}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
96
ext/fts5/test/fts5first.test
Normal file
96
ext/fts5/test/fts5first.test
Normal file
@@ -0,0 +1,96 @@
|
||||
# 2017 November 25
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
|
||||
source [file join [file dirname [info script]] fts5_common.tcl]
|
||||
set testprefix fts5first
|
||||
|
||||
ifcapable !fts5 {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE VIRTUAL TABLE x1 USING fts5(a, b);
|
||||
}
|
||||
|
||||
foreach {tn expr ok} {
|
||||
1 {^abc} 1
|
||||
2 {^abc + def} 1
|
||||
3 {^ "abc def"} 1
|
||||
4 {^"abc def"} 1
|
||||
5 {abc ^def} 1
|
||||
6 {abc + ^def} 0
|
||||
7 {abc ^+ def} 0
|
||||
8 {"^abc"} 1
|
||||
9 {NEAR(^abc def)} 0
|
||||
} {
|
||||
set res(0) {/1 {fts5: syntax error near .*}/}
|
||||
set res(1) {0 {}}
|
||||
|
||||
do_catchsql_test 1.$tn { SELECT * FROM x1($expr) } $res($ok)
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
do_execsql_test 2.0 {
|
||||
INSERT INTO x1 VALUES('a b c', 'b c a');
|
||||
}
|
||||
|
||||
foreach {tn expr match} {
|
||||
1 {^a} 1
|
||||
2 {^b} 1
|
||||
3 {^c} 0
|
||||
4 {^a + b} 1
|
||||
5 {^b + c} 1
|
||||
6 {^c + a} 0
|
||||
7 {^"c a"} 0
|
||||
8 {a:^a} 1
|
||||
9 {a:^b} 0
|
||||
10 {a:^"a b"} 1
|
||||
} {
|
||||
do_execsql_test 2.$tn { SELECT EXISTS (SELECT rowid FROM x1($expr)) } $match
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
do_execsql_test 3.0 {
|
||||
DELETE FROM x1;
|
||||
INSERT INTO x1 VALUES('b a', 'c a');
|
||||
INSERT INTO x1 VALUES('a a', 'c c');
|
||||
INSERT INTO x1 VALUES('a b', 'a a');
|
||||
}
|
||||
fts5_aux_test_functions db
|
||||
|
||||
foreach {tn expr expect} {
|
||||
1 {^a} {{2 1}}
|
||||
2 {^c AND ^b} {{0 2} {1 0}}
|
||||
} {
|
||||
do_execsql_test 3.$tn {
|
||||
SELECT fts5_test_queryphrase(x1) FROM x1($expr) LIMIT 1
|
||||
} [list $expect]
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
do_execsql_test 3.1 {
|
||||
CREATE VIRTUAL TABLE x2 USING fts5(a, b, c, detail=column);
|
||||
}
|
||||
|
||||
do_catchsql_test 3.2 {
|
||||
SELECT * FROM x2('a + b');
|
||||
} {1 {fts5: phrase queries are not supported (detail!=full)}}
|
||||
|
||||
do_catchsql_test 3.3 {
|
||||
SELECT * FROM x2('^a');
|
||||
} {1 {fts5: phrase queries are not supported (detail!=full)}}
|
||||
finish_test
|
||||
|
||||
21
manifest
21
manifest
@@ -1,5 +1,5 @@
|
||||
C Enhance\sthe\sconfigure\sscript\sto\sdetect\szLib.
|
||||
D 2017-11-24T16:55:48.156
|
||||
C Add\sthe\s"^"\ssyntax\sfrom\sfts3/4\sto\sfts5.
|
||||
D 2017-11-24T19:24:44.918
|
||||
F Makefile.in 6a879cbf01e37f9eac131414955f71774b566502d9a57ded1b8585b507503cb8
|
||||
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
|
||||
F Makefile.msc e5d7606238f55816da99f719969598df5b091aa2e9a6935c9412fcae8f53fc44
|
||||
@@ -99,11 +99,11 @@ F ext/fts3/unicode/mkunicode.tcl ab0543a3b2399092ea2dd75df1bef333405b0d7f6b8c495
|
||||
F ext/fts3/unicode/parseunicode.tcl da577d1384810fb4e2b209bf3313074353193e95
|
||||
F ext/fts5/extract_api_docs.tcl a36e54ec777172ddd3f9a88daf593b00848368e0
|
||||
F ext/fts5/fts5.h 62f3e33ceeb9a428db139f9c012186b371da1cc7
|
||||
F ext/fts5/fts5Int.h 15e7514b46a845937d7c62e5c69e935091f0dbb72eb61aa4c8bcfbd39fdea158
|
||||
F ext/fts5/fts5Int.h eda28e3a0a5d87c412e8355fe35da875b04cb389908c8eb0d867ad662adbc491
|
||||
F ext/fts5/fts5_aux.c 67acf8d51723cf28ffc3828210ba662df4b8d267
|
||||
F ext/fts5/fts5_buffer.c 1dd1ec0446b3acfc2d7d407eb894762a461613e2695273f48e449bfd13e973ff
|
||||
F ext/fts5/fts5_config.c 5af9c360e99669d29f06492c370892394aba0857
|
||||
F ext/fts5/fts5_expr.c f2825f714d91bbe62ab5820aee9ad12e0c94205b2a01725eaa9072415ae9ff1c
|
||||
F ext/fts5/fts5_expr.c 01048018d21524e2c302b063ff5c3cdcf546e03297215e577205d85b47499deb
|
||||
F ext/fts5/fts5_hash.c 32be400cf761868c9db33efe81a06eb19a17c5402ad477ee9efb51301546dd55
|
||||
F ext/fts5/fts5_index.c 2ce9d50ec5508b8205615aad69e1c9b2c77f017f21d4479e1fb2079c01fdd017
|
||||
F ext/fts5/fts5_main.c 24868f88ab2a865defbba7a92eebeb726cc991eb092b71b5f5508f180c72605b
|
||||
@@ -115,7 +115,7 @@ F ext/fts5/fts5_tokenize.c 2ce7b44183538ec46b7907726262ee43ffdd39a8
|
||||
F ext/fts5/fts5_unicode2.c b450b209b157d598f7b9df9f837afb75a14c24bf
|
||||
F ext/fts5/fts5_varint.c a5aceacda04dafcbae725413d7a16818ecd65738
|
||||
F ext/fts5/fts5_vocab.c 1cd79854cb21543e66507b25b0578bc1b20aa6a1349b7feceb8e8fed0e7a77a6
|
||||
F ext/fts5/fts5parse.y a070b538e08ae9e2177d15c337ed2a3464408f0f886e746307098f746efd94ca
|
||||
F ext/fts5/fts5parse.y eb526940f892ade5693f22ffd6c4f2702543a9059942772526eac1fde256bb05
|
||||
F ext/fts5/mkportersteps.tcl 5acf962d2e0074f701620bb5308155fa1e4a63ba
|
||||
F ext/fts5/test/fts5_common.tcl b01c584144b5064f30e6c648145a2dd6bc440841
|
||||
F ext/fts5/test/fts5aa.test cba3fae6466446980caf1b9f5f26df77f95a999d35db7d932d6e82ae7ba0ede9
|
||||
@@ -162,8 +162,9 @@ F ext/fts5/test/fts5fault7.test 0acbec416edb24b8881f154e99c31e9ccf73f539cfcd1640
|
||||
F ext/fts5/test/fts5fault8.test 318238659d35f82ad215ecb57ca4c87486ea85d45dbeedaee42f148ff5105ee2
|
||||
F ext/fts5/test/fts5fault9.test 0111b229388bdf251b91cfead68580227801dd30960a19aa8fe9021a1e73cb6d
|
||||
F ext/fts5/test/fts5faultA.test be4487576bff8c22cee6597d1893b312f306504a8c6ccd3c53ca85af12290c8c
|
||||
F ext/fts5/test/fts5faultB.test 28810d93d37b59ebd5cf9502897f4dc9e6adb8ea6a5f64e125d3088597199d0d
|
||||
F ext/fts5/test/fts5faultB.test e6d04f9ea7b21be1d89abb8df2cb4baf65b0453b744d5a805fcd3ef45ff86a7e
|
||||
F ext/fts5/test/fts5faultD.test cc5d1225556e356615e719c612e845d41bff7d5a
|
||||
F ext/fts5/test/fts5first.test 707a591b1b7d893fcfcb2366cbfe56aefab5d9c7cfa58bef35eba73a1dbf3b29
|
||||
F ext/fts5/test/fts5full.test 49b565da02918c06e58f51f0b953b0302b96f155aa68baba24782b81570685e2
|
||||
F ext/fts5/test/fts5fuzz1.test 238d8c45f3b81342aa384de3e581ff2fa330bf922a7b69e484bbc06051a1080e
|
||||
F ext/fts5/test/fts5hash.test a4cf51acad99bfc43c16fb74f9d22495dc221ae0701fc5e908ca963a9b26a02b
|
||||
@@ -1677,7 +1678,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||
P b016c28fa5617a20ad34c005372e738d28f7fc4388d19ee0cb7add4ed19d74aa
|
||||
R 32193c0299a7059451a8ff25bb895cce
|
||||
U drh
|
||||
Z 88a3edc8b736c2bf1f1a3f732d1a86ca
|
||||
P e3b6e22049caf78bc4153ded8dc295fe30ad320323d921f16bd794ef30f1b115
|
||||
R dd0642a6cc4628ee924c556518e62685
|
||||
U dan
|
||||
Z b13dcd2f6b4a5ff1701c0fa74c45ed53
|
||||
|
||||
@@ -1 +1 @@
|
||||
e3b6e22049caf78bc4153ded8dc295fe30ad320323d921f16bd794ef30f1b115
|
||||
24d7058e2799133dd681d2fef341025ca50554861bb4cd39e93ee87ae1d8a605
|
||||
Reference in New Issue
Block a user