From: dan Date: Sat, 5 Jul 2014 15:15:41 +0000 (+0000) Subject: Add support for AND, OR and NOT to fts5. X-Git-Tag: version-3.8.11~114^2~169 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=103576dd75bf97634a65877b21b156412722c636;p=thirdparty%2Fsqlite.git Add support for AND, OR and NOT to fts5. FossilOrigin-Name: 8682b87e794767cefcaa080fd53c8973c24c556a --- diff --git a/ext/fts5/fts5_expr.c b/ext/fts5/fts5_expr.c index 8a84f958ba..e528757bb4 100644 --- a/ext/fts5/fts5_expr.c +++ b/ext/fts5/fts5_expr.c @@ -317,14 +317,6 @@ void sqlite3Fts5ExprFree(Fts5Expr *p){ } } -/* -** -*/ -static int fts5ExprNodeTest(Fts5Expr *pExpr, Fts5ExprNode *pNode){ - assert( 0 ); - return SQLITE_OK; -} - /* ** All individual term iterators in pPhrase are guaranteed to be valid and ** pointing to the same rowid when this function is called. This function @@ -462,8 +454,8 @@ static int fts5ExprNearIsMatch(Fts5ExprNearset *pNear, int *pbMatch){ } /* -** Advance each phrase iterator in phrase pNear. If any reach EOF, set -** output variable *pbEof to true before returning. +** Advance each term iterator in each phrase in pNear. If any reach EOF, +** set output variable *pbEof to true before returning. */ static int fts5ExprNearAdvanceAll( Fts5Expr *pExpr, /* Expression pPhrase belongs to */ @@ -650,17 +642,131 @@ static int fts5ExprNearInitAll( return SQLITE_OK; } -static int fts5ExprNearNext( - Fts5Expr *pExpr, /* Expression that pNear is a part of */ - Fts5ExprNode *pNode -){ - int rc = fts5ExprNearAdvanceAll(pExpr, pNode->pNear, &pNode->bEof); - if( rc==SQLITE_OK && pNode->bEof==0 ){ - rc = fts5ExprNearNextMatch(pExpr, pNode); +/* fts3ExprNodeNext() calls fts5ExprNodeNextMatch(). And vice-versa. */ +static int fts5ExprNodeNextMatch(Fts5Expr*, Fts5ExprNode*); + +/* +** Nodes at EOF are considered larger than all other nodes. A node that +** points to a *smaller* rowid is considered larger. +** +** res = (*p1) - (*p2) +*/ +static int fts5NodeCompare(Fts5ExprNode *p1, Fts5ExprNode *p2){ + if( p2->bEof ) return -1; + if( p1->bEof ) return +1; + if( p1->iRowid>p2->iRowid ) return -1; + return (p1->iRowid < p2->iRowid); +} + +static int fts5ExprNodeNext(Fts5Expr *pExpr, Fts5ExprNode *pNode){ + int rc = SQLITE_OK; + + if( pNode->bEof==0 ){ + switch( pNode->eType ){ + case FTS5_STRING: { + rc = fts5ExprNearAdvanceAll(pExpr, pNode->pNear, &pNode->bEof); + break; + }; + + case FTS5_AND: { + rc = fts5ExprNodeNext(pExpr, pNode->pLeft); + if( rc==SQLITE_OK ) rc = fts5ExprNodeNext(pExpr, pNode->pRight); + break; + } + + case FTS5_OR: { + Fts5ExprNode *p1 = pNode->pLeft; + Fts5ExprNode *p2 = pNode->pRight; + int cmp = fts5NodeCompare(p1, p2); + + if( cmp==0 ){ + rc = fts5ExprNodeNext(pExpr, p1); + if( rc==SQLITE_OK ) rc = fts5ExprNodeNext(pExpr, p2); + }else{ + rc = fts5ExprNodeNext(pExpr, (cmp < 0) ? p1 : p2); + } + + break; + } + + default: assert( pNode->eType==FTS5_NOT ); { + rc = fts5ExprNodeNext(pExpr, pNode->pLeft); + break; + } + } + + if( rc==SQLITE_OK ){ + rc = fts5ExprNodeNextMatch(pExpr, pNode); + } } + return rc; } + +/* +** +*/ +static int fts5ExprNodeNextMatch(Fts5Expr *pExpr, Fts5ExprNode *pNode){ + int rc = SQLITE_OK; + if( pNode->bEof==0 ){ + switch( pNode->eType ){ + + case FTS5_STRING: { + rc = fts5ExprNearNextMatch(pExpr, pNode); + break; + } + + case FTS5_AND: { + Fts5ExprNode *p1 = pNode->pLeft; + Fts5ExprNode *p2 = pNode->pRight; + + while( p1->bEof==0 && p2->bEof==0 && p2->iRowid!=p1->iRowid ){ + Fts5ExprNode *pAdv = (p1->iRowid > p2->iRowid) ? p1 : p2; + rc = fts5ExprNodeNext(pExpr, pAdv); + if( rc!=SQLITE_OK ) break; + } + pNode->bEof = p1->bEof || p2->bEof; + pNode->iRowid = p1->iRowid; + break; + } + + case FTS5_OR: { + Fts5ExprNode *p1 = pNode->pLeft; + Fts5ExprNode *p2 = pNode->pRight; + Fts5ExprNode *pNext = (fts5NodeCompare(p1, p2) > 0 ? p2 : p1); + pNode->bEof = pNext->bEof; + pNode->iRowid = pNext->iRowid; + break; + } + + default: assert( pNode->eType==FTS5_NOT ); { + Fts5ExprNode *p1 = pNode->pLeft; + Fts5ExprNode *p2 = pNode->pRight; + while( rc==SQLITE_OK ){ + int cmp; + while( rc==SQLITE_OK && (cmp = fts5NodeCompare(p1, p2))>0 ){ + rc = fts5ExprNodeNext(pExpr, p2); + } + if( rc || cmp ) break; + rc = fts5ExprNodeNext(pExpr, p1); + } + pNode->bEof = p1->bEof; + pNode->iRowid = p1->iRowid; + break; + } + } + } + return rc; +} + +/* +** Set node pNode, which is part of expression pExpr, to point to the first +** match. If there are no matches, set the Node.bEof flag to indicate EOF. +** +** Return an SQLite error code if an error occurs, or SQLITE_OK otherwise. +** It is not an error if there are no matches. +*/ static int fts5ExprNodeFirst(Fts5Expr *pExpr, Fts5ExprNode *pNode){ int rc = SQLITE_OK; pNode->bEof = 0; @@ -681,23 +787,12 @@ static int fts5ExprNodeFirst(Fts5Expr *pExpr, Fts5ExprNode *pNode){ rc = fts5ExprNodeFirst(pExpr, pNode->pRight); } if( rc==SQLITE_OK ){ - rc = fts5ExprNodeTest(pExpr, pNode); + rc = fts5ExprNodeNextMatch(pExpr, pNode); } } return rc; } -static int fts5ExprNodeNext(Fts5Expr *pExpr, Fts5ExprNode *pNode){ - int rc = SQLITE_OK; - - if( pNode->eType==FTS5_STRING ){ - rc = fts5ExprNearNext(pExpr, pNode); - }else{ - assert( 0 ); - } - return rc; -} - /* diff --git a/manifest b/manifest index 0526a1e9b9..f794442bda 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\ssupport\sfor\sthe\s"colname\s:\s"\ssyntax\sto\sfts5. -D 2014-07-05T07:54:01.680 +C Add\ssupport\sfor\sAND,\sOR\sand\sNOT\sto\sfts5. +D 2014-07-05T15:15:41.850 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in b03432313a3aad96c706f8164fb9f5307eaf19f5 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -107,7 +107,7 @@ F ext/fts5/fts5.c 1af3184dd9c0e5c1686f71202d6b6cac8f225f05 F ext/fts5/fts5Int.h b7a684ff3508ab24437886f8bc873a16f494a7db F ext/fts5/fts5_buffer.c f1a26a79e2943fe4388e531fa141941b5eb6d31a F ext/fts5/fts5_config.c 94f1b4cb4de6a7cd5780c14adb0198e289df8cef -F ext/fts5/fts5_expr.c 618e6641c8dc428c146ec84bf30ff0b3da6b28c7 +F ext/fts5/fts5_expr.c a341fe4f6d49875a7aeaa443036a3dc6aa2bff52 F ext/fts5/fts5_index.c d8ab9712e38dc1beb9a9145ec89e18dc083c0467 F ext/fts5/fts5_storage.c 7848d8f8528d798bba159900ea310a6d4a279da8 F ext/icu/README.txt d9fbbad0c2f647c3fdf715fc9fd64af53aedfc43 @@ -594,7 +594,7 @@ F test/fts4noti.test 524807f0c36d49deea7920cdd4cd687408b58849 F test/fts4unicode.test 01ec3fe2a7c3cfff3b4c0581b83caa11b33efa36 F test/fts5aa.test c8d3b9694f6b2864161c7437408464a535d19343 F test/fts5ab.test 4db86a9473ee2a8c2cb30e0d81df21c6022f99b6 -F test/fts5ac.test c7ca34a477d638195a839c961e1b572890dc5d0d +F test/fts5ac.test d3aeb7a079d40093b34ac8053fc5e4c0ed7e88dc F test/fts5ea.test ff43b40f8879ba50b82def70f2ab67c195d1a1d4 F test/full.test 6b3c8fb43c6beab6b95438c1675374b95fab245d F test/func.test ae97561957aba6ca9e3a7b8a13aac41830d701ef @@ -1190,7 +1190,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 250ae8d40115e2e47cc5a1e8a427fa8c0a89124d -R 213fb14ea45e358dcb308401853c4570 +P 004667106e552e832a564b77e242b86f183d4441 +R 4ab8db5e873de873b3febadf2e9942c6 U dan -Z 0b8632fefc20738326985d3c409c9be8 +Z fcdcd2fcf8de98f33f86410b0c7d6d38 diff --git a/manifest.uuid b/manifest.uuid index 506ee6aff0..3630392fc9 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -004667106e552e832a564b77e242b86f183d4441 \ No newline at end of file +8682b87e794767cefcaa080fd53c8973c24c556a \ No newline at end of file diff --git a/test/fts5ac.test b/test/fts5ac.test index c4586481bf..849ea52e5e 100644 --- a/test/fts5ac.test +++ b/test/fts5ac.test @@ -208,7 +208,7 @@ proc nearset {aCol args} { return $bMatch } -proc matchdata {expr} { +proc matchdata {expr {print 0}} { set tclexpr [db one {SELECT fts5_expr_tcl($expr, 'nearset $cols', 'x', 'y')}] set res [list] foreach {id x y} $::data { @@ -217,6 +217,9 @@ proc matchdata {expr} { set res [concat $id $res] } } + if {$print} { + puts $tclexpr + } return $res } @@ -272,10 +275,18 @@ foreach {tn expr} { 9 { y : NEAR(r c) } 10 { x : "r c" } 11 { y : "r c" } + 12 { a AND b } + 13 { a AND b AND c } + 14a { a } + 14b { a OR b } + 15 { a OR b AND c } + 16 { c AND b OR a } + 17 { c AND (b OR a) } + 18 { c NOT (b OR a) } + 19 { c NOT b OR a AND d } } { - set res [matchdata $expr] - do_execsql_test 2.$tn.[llength $res] { + do_execsql_test 4.$tn.[llength $res] { SELECT rowid FROM xx WHERE xx match $expr } $res }