** See xPhraseFirst above.
*/
struct Fts5ExtensionApi {
- int iVersion; /* Currently always set to 2 */
+ int iVersion; /* Currently always set to 3 */
void *(*xUserData)(Fts5Context*);
int (*xSetAuxdata)(Fts5Context*, void *pAux, void(*xDelete)(void*));
void *(*xGetAuxdata)(Fts5Context*, int bClear);
- void (*xPhraseFirst)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*, int*);
+ int (*xPhraseFirst)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*, int*);
void (*xPhraseNext)(Fts5Context*, Fts5PhraseIter*, int *piCol, int *piOff);
+
+ int (*xPhraseFirstColumn)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*);
+ void (*xPhraseNextColumn)(Fts5Context*, Fts5PhraseIter*, int *piCol);
};
/*
int sqlite3Fts5IndexLoadConfig(Fts5Index *p);
+int sqlite3Fts5IterCollist(Fts5IndexIter*, const u8 **, int*);
+
/*
** End of interface to code in fts5_index.c.
**************************************************************************/
int sqlite3Fts5ExprClonePhrase(Fts5Config*, Fts5Expr*, int, Fts5Expr**);
+int sqlite3Fts5ExprPhraseCollist(Fts5Expr *, int, const u8 **, int *);
+
/*******************************************
** The fts5_expr.c API above this point is used by the other hand-written
** C code in this module. The interfaces below this point are called by
);
}
+/*
+** This function is only called for detail=columns tables.
+*/
+int sqlite3Fts5ExprPhraseCollist(
+ Fts5Expr *pExpr,
+ int iPhrase,
+ const u8 **ppCollist,
+ int *pnCollist
+){
+ Fts5ExprPhrase *pPhrase = pExpr->apExprPhrase[iPhrase];
+ Fts5ExprNode *pNode = pPhrase->pNode;
+ assert( iPhrase>=0 && iPhrase<pExpr->nPhrase );
+
+ if( pNode->bEof==0 && pNode->iRowid==pExpr->pRoot->iRowid ){
+ sqlite3Fts5IterCollist(pPhrase->aTerm[0].pIter, ppCollist, pnCollist);
+ }else{
+ *ppCollist = 0;
+ *pnCollist = 0;
+ }
+ return SQLITE_OK;
+}
+
return fts5IndexReturn(pIter->pIndex);
}
+int sqlite3Fts5IterCollist(
+ Fts5IndexIter *pIter,
+ const u8 **pp, /* OUT: Pointer to position-list data */
+ int *pn /* OUT: Size of position-list in bytes */
+){
+ assert( pIter->pIndex->pConfig->eDetail==FTS5_DETAIL_COLUMNS );
+ *pp = pIter->poslist.p;
+ *pn = pIter->poslist.n;
+ return SQLITE_OK;
+}
+
/*
** This function is similar to sqlite3Fts5IterPoslist(), except that it
** copies the position list into the buffer supplied as the second
if( pIter->a>=pIter->b ){
*piCol = -1;
*piOff = -1;
-#if 0
- }else if( fts5IsOffsetless((Fts5Table*)(((Fts5Cursor*)pCtx)->base.pVtab)) ){
- int iVal;
- pIter->a += fts5GetVarint32(pIter->a, iVal);
- *piCol += (iVal-2);
- *piOff = -1;
-#endif
}else{
int iVal;
pIter->a += fts5GetVarint32(pIter->a, iVal);
}
}
-static void fts5ApiPhraseFirst(
+static int fts5ApiPhraseFirst(
Fts5Context *pCtx,
int iPhrase,
Fts5PhraseIter *pIter,
fts5ApiPhraseNext(pCtx, pIter, piCol, piOff);
}
+static void fts5ApiPhraseNextColumn(
+ Fts5Context *pCtx,
+ Fts5PhraseIter *pIter,
+ int *piCol
+){
+ Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
+ Fts5Config *pConfig = ((Fts5Table*)(pCsr->base.pVtab))->pConfig;
+
+ if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){
+ if( pIter->a>=pIter->b ){
+ *piCol = -1;
+ }else{
+ int iIncr;
+ pIter->a += fts5GetVarint32(&pIter->a[0], iIncr);
+ *piCol += (iIncr-2);
+ }
+ }else{
+ while( 1 ){
+ int dummy;
+ if( pIter->a>=pIter->b ){
+ *piCol = -1;
+ return;
+ }
+ if( pIter->a[0]==0x01 ) break;
+ pIter->a += fts5GetVarint32(pIter->a, dummy);
+ }
+ pIter->a += 1 + fts5GetVarint32(&pIter->a[1], *piCol);
+ }
+}
+
+static int fts5ApiPhraseFirstColumn(
+ Fts5Context *pCtx,
+ int iPhrase,
+ Fts5PhraseIter *pIter,
+ int *piCol
+){
+ int rc = SQLITE_OK;
+ Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
+ Fts5Config *pConfig = ((Fts5Table*)(pCsr->base.pVtab))->pConfig;
+
+ if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){
+ int n;
+ rc = sqlite3Fts5ExprPhraseCollist(pCsr->pExpr, iPhrase, &pIter->a, &n);
+ if( rc==SQLITE_OK ){
+ pIter->b = &pIter->a[n];
+ *piCol = 0;
+ fts5ApiPhraseNextColumn(pCtx, pIter, piCol);
+ }
+ }else{
+ int n = fts5CsrPoslist(pCsr, iPhrase, &pIter->a);
+ pIter->b = &pIter->a[n];
+ if( n<=0 ){
+ *piCol = -1;
+ }else if( pIter->a[0]==0x01 ){
+ pIter->a += 1 + fts5GetVarint32(&pIter->a[1], *piCol);
+ }else{
+ *piCol = 0;
+ }
+ }
+
+ return rc;
+}
+
+
static int fts5ApiQueryPhrase(Fts5Context*, int, void*,
int(*)(const Fts5ExtensionApi*, Fts5Context*, void*)
);
fts5ApiGetAuxdata,
fts5ApiPhraseFirst,
fts5ApiPhraseNext,
+ fts5ApiPhraseFirstColumn,
+ fts5ApiPhraseNextColumn,
};
/*
{ "xSetAuxdataInt", 1, "INTEGER" }, /* 14 */
{ "xGetAuxdataInt", 1, "CLEAR" }, /* 15 */
{ "xPhraseForeach", 4, "IPHRASE COLVAR OFFVAR SCRIPT" }, /* 16 */
+ { "xPhraseColumnForeach", 3, "IPHRASE COLVAR SCRIPT" }, /* 17 */
{ 0, 0, 0}
};
break;
}
+ CASE(17, "xPhraseColumnForeach") {
+ int iPhrase;
+ int iCol;
+ const char *zColvar;
+ Tcl_Obj *pScript = objv[4];
+ Fts5PhraseIter iter;
+
+ if( Tcl_GetIntFromObj(interp, objv[2], &iPhrase) ) return TCL_ERROR;
+ zColvar = Tcl_GetString(objv[3]);
+
+ for(p->pApi->xPhraseFirstColumn(p->pFts, iPhrase, &iter, &iCol);
+ iCol>=0;
+ p->pApi->xPhraseNextColumn(p->pFts, &iter, &iCol)
+ ){
+ Tcl_SetVar2Ex(interp, zColvar, 0, Tcl_NewIntObj(iCol), 0);
+ rc = Tcl_EvalObjEx(interp, pScript, 0);
+ if( rc==TCL_CONTINUE ) rc = TCL_OK;
+ if( rc!=TCL_OK ){
+ if( rc==TCL_BREAK ) rc = TCL_OK;
+ break;
+ }
+ }
+
+ break;
+ }
+
default:
assert( 0 );
break;
set res
}
+proc fts5_test_collist {cmd} {
+ set res [list]
+
+ for {set i 0} {$i < [$cmd xPhraseCount]} {incr i} {
+ $cmd xPhraseColumnForeach $i c { lappend res $i.$c }
+ }
+
+ set res
+}
+
proc fts5_test_columnsize {cmd} {
set res [list]
for {set i 0} {$i < [$cmd xColumnCount]} {incr i} {
fts5_test_columntotalsize
fts5_test_poslist
fts5_test_poslist2
+ fts5_test_collist
fts5_test_tokenize
fts5_test_rowcount
fts5_test_all
# CREATE VIRTUAL TABLE xy USING fts5(x, y);
#
# Assuming the table contains the same records as stored in the global
-# $::data array (see above), this function returns a list containing one
-# element for each match in the dataset. The elements are themselves lists
-# formatted as follows:
+# $::data array (see above), this function returns a list containing two
+# elements for each matching row in the dataset. The first element of each
+# pair is the rowid. The second is a list of phrase matches, where each
+# phrase match is of the form:
#
-# <rowid> {<phrase 0 matches> <phrase 1 matches>...}
+# <phrase-number>.<column-number>.<offset>
#
-# where each <phrase X matches> element is a list of phrase matches in the
-# same form as returned by auxiliary scalar function fts5_test().
+# The list of phrase matches is in the same format as that returned by the
+# fts5_test_poslist() auxiliary scalara function.
#
-proc matchdata {bPos expr {bAsc 1}} {
+proc poslist_data {bPos expr {bAsc 1}} {
set tclexpr [db one {
SELECT fts5_expr_tcl($expr, 'nearset $cols -pc ::pc', 'x', 'y')
set res [lsort -integer -decreasing -index 0 $res]
}
- return [concat {*}$res]
+ set res [concat {*}$res]
+ return $res
+}
+
+proc collist_elem_compare {a b} {
+ foreach {a1 a2} [split $a .] {}
+ foreach {b1 b2} [split $b .] {}
+
+ if {$a1==$b1} {
+ return [expr $a2 - $b2]
+ }
+ return [expr $a1 - $b1]
+}
+
+proc poslist2collist {poslist} {
+ set res [list]
+ foreach h $poslist {
+ regexp {(.*)\.[1234567890]+} $h -> cand
+ lappend res $cand
+ }
+ set res [lsort -command collist_elem_compare -unique $res]
+ return $res
+}
+
+proc collist_data {expr} {
+ set res [list]
+ foreach {rowid poslist} [poslist_data 1 $expr] {
+ lappend res $rowid [poslist2collist $poslist]
+ }
+ set res
}
#
# End of test code
#-------------------------------------------------------------------------
+if 0 {
foreach {tn2 sql} {
1 {}
10 "L O O L V V K"
} {
set expr "\"$phrase\""
- set res [matchdata 1 $expr]
+ set res [poslist_data 1 $expr]
- do_execsql_test 1.$tn2.1.2.$tn.[llength $res] {
+ do_execsql_test 1.$tn2.1.2.$tn.p.[llength $res] {
SELECT rowid, fts5_test_poslist(xx) FROM xx WHERE xx match $expr
} $res
+
+ set res [collist_data $expr]
+ do_execsql_test 1.$tn2.1.2.$tn.c.[llength $res] {
+ SELECT rowid, fts5_test_collist(xx) FROM xx WHERE xx match $expr
+ } $res
}
#-------------------------------------------------------------------------
3.1 { a AND b AND c }
} {
- set res [matchdata 1 $expr]
- do_execsql_test 1.$tn2.2.$tn.[llength $res] {
+ set res [poslist_data 1 $expr]
+ do_execsql_test 1.$tn2.2.$tn.c.[llength $res] {
SELECT rowid, fts5_test_poslist(xx) FROM xx WHERE xx match $expr
} $res
+
+ set res [collist_data $expr]
+ do_execsql_test 1.$tn2.2.$tn.c.[llength $res] {
+ SELECT rowid, fts5_test_collist(xx) FROM xx WHERE xx match $expr
+ } $res
}
#-------------------------------------------------------------------------
4.3 {{x "x"}:b}
4.4 {{"y" y}:b}
} {
- set res [matchdata 1 $expr]
- do_execsql_test 1.$tn2.3.$tn.[llength $res] {
+ set res [poslist_data 1 $expr]
+ do_execsql_test 1.$tn2.3.$tn.p.[llength $res] {
SELECT rowid, fts5_test_poslist(xx) FROM xx WHERE xx match $expr
} $res
+
+ set res [collist_data $expr]
+ do_execsql_test 1.$tn2.3.$tn.c.[llength $res] {
+ SELECT rowid, fts5_test_collist(xx) FROM xx WHERE xx match $expr
+ } $res
}
#-------------------------------------------------------------------------
8 { x : NEAR(r c) }
9 { y : NEAR(r c) }
} {
- set res [matchdata 1 $expr]
- do_execsql_test 1.$tn2.4.1.$tn.[llength $res] {
+ set res [poslist_data 1 $expr]
+ do_execsql_test 1.$tn2.4.1.$tn.p.[llength $res] {
SELECT rowid, fts5_test_poslist(xx) FROM xx WHERE xx match $expr
} $res
+
+ set res [collist_data $expr]
+ do_execsql_test 1.$tn2.4.1.$tn.c.[llength $res] {
+ SELECT rowid, fts5_test_collist(xx) FROM xx WHERE xx match $expr
+ } $res
}
do_test $tn2.4.1 { nearset {{a b c}} -- a } {0.0.0}
18 { c NOT (b OR a) }
19 { c NOT b OR a AND d }
} {
- set res [matchdata 0 $expr $bAsc]
+ set res [poslist_data 0 $expr $bAsc]
do_execsql_test 1.$tn2.6.$bAsc.$tn.[llength $res] $sql $res
}
}
SELECT fts5_expr_tcl('a AND b');
} {{AND [nearset -- {a}] [nearset -- {b}]}}
+}
+#set data [lrange $data 0 5]
+
# Some tests for detail=col tables and detail=none.
#
foreach {tn2 sql} {
INSERT INTO xx(xx, rank) VALUES('pgsz', 32);
}
-
do_test 3.$tn2.1.1 {
foreach {id x y} $data {
execsql { INSERT INTO xx(rowid, x, y) VALUES($id, $x, $y) }
foreach {tn q} {
1 "o" 2 "b" 3 "e" 4 "m" 5 "l" 6 "a" 7 "b" 8 "c" 9 "no" 10 "L"
- 11 "o a" 12 "c AND d" 13 "o OR a" 12 "c OR d"
+ 11 "o a" 12 "c AND d" 13 "o OR a" 14 "c OR d"
} {
- set res [matchdata 1 $q]
-
- do_execsql_test 3.$tn2.1.2.$tn.[llength $res] {
+ set res [poslist_data 1 $q]
+ do_execsql_test 3.$tn2.1.2.$tn.p.[llength $res] {
SELECT rowid, fts5_test_poslist(xx) FROM xx WHERE xx match $q
} $res
+
+ set res [collist_data $q]
+ do_execsql_test 3.$tn2.1.2.$tn.c.[llength $res] {
+ SELECT rowid, fts5_test_collist(xx) FROM xx WHERE xx match $q
+ } $res
}
}
-C Change\sthe\sname\sof\sthe\soffsets=0\soption\sto\s"detail=column".\sHave\sthe\sxInst,\sxPhraseFirst\sand\sother\sAPI\sfunctions\swork\sby\sparsing\sthe\soriginal\stext\sfor\sdetail=column\stables.
-D 2015-12-28T19:55:00.739
+C Add\sthe\sxPhraseFirstColumn()\sand\sxPhraseNextColumn()\sAPI\sfunctions\sto\sfts5.\sFor\siterating\sthrough\sthe\sset\sof\scolumns\sthat\scontain\sintances\sof\sa\sphrase.
+D 2015-12-29T19:35:03.765
F Makefile.in 28bcd6149e050dff35d4dcfd97e890cd387a499d
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
F Makefile.msc 5fff077fcc46de7714ed6eebb6159a4c00eab751
F ext/fts3/unicode/mkunicode.tcl 95cf7ec186e48d4985e433ff8a1c89090a774252
F ext/fts3/unicode/parseunicode.tcl da577d1384810fb4e2b209bf3313074353193e95
F ext/fts5/extract_api_docs.tcl a36e54ec777172ddd3f9a88daf593b00848368e0
-F ext/fts5/fts5.h 7d6785c75afe23239dad9cbaffc6fc55803feb4b
-F ext/fts5/fts5Int.h 7328cfa7b0151e34bb3715d404d732c6d49d5361
+F ext/fts5/fts5.h 88fec577a2148f34df75930dc2b0c45b0bad72c3
+F ext/fts5/fts5Int.h ab5f6f1f65652310a644d97d12aeabf8ab5ed17e
F ext/fts5/fts5_aux.c 1f384972d606375b8fa078319f25ab4b5feb1b35
F ext/fts5/fts5_buffer.c 87204c8b3b8bc62b27376eab09b74d6d5acc41f1
F ext/fts5/fts5_config.c b0ed7b0ddd785fb4d4e6f9037d357f8aa95918e6
-F ext/fts5/fts5_expr.c c9522ae99f862ddb318ea69998a02147d2a00c8d
+F ext/fts5/fts5_expr.c 08ee4f342a2b1fd82a5dccd0b9b3cde4921a8be5
F ext/fts5/fts5_hash.c 8b510868502ec31119409fc7022edc37c27b5c40
-F ext/fts5/fts5_index.c 24e81d8f2ce92f50eb19c15bffd5ada4ec91d8de
-F ext/fts5/fts5_main.c a71db65929e150031c5a195e3c782e773deb55a6
+F ext/fts5/fts5_index.c ca8310eaa286e6c1e4c4581a420b7c3a1ec6302c
+F ext/fts5/fts5_main.c 23f3912ff44172859c771eb55cb57778fd662e89
F ext/fts5/fts5_storage.c 076a3356536a8831eb6e554195171d5c249cd179
-F ext/fts5/fts5_tcl.c c3cfff5f727b3d02f73c5717413d637b18b960f2
+F ext/fts5/fts5_tcl.c 18e9382d8cdad4c05b49559c68494968b9b4a4fb
F ext/fts5/fts5_test_mi.c c9c8cf455c49ded156a234e0de1c8ba9be85e5c3
F ext/fts5/fts5_tokenize.c 618efe033bceb80c521b1e9ddfd9fee85fb5946e
F ext/fts5/fts5_unicode2.c 78273fbd588d1d9bd0a7e4e0ccc9207348bae33c
F ext/fts5/fts5_vocab.c 3742d0abfe8aa8c3cb4a7df56aa38f2e3c3fb1c2
F ext/fts5/fts5parse.y 1647eba089b9b3fc058b4dc989d9da87d15b9580
F ext/fts5/mkportersteps.tcl 5acf962d2e0074f701620bb5308155fa1e4a63ba
-F ext/fts5/test/fts5_common.tcl 27f941596e241e25b4bd64c2446ae91dd4cb138c
+F ext/fts5/test/fts5_common.tcl f923471d572d1e283b7d6985ce3cda62dae6fd45
F ext/fts5/test/fts5aa.test 2c553eea4dab4bc5a75928f56729277c7bc1d206
F ext/fts5/test/fts5ab.test 6fe3a56731d15978afbb74ae51b355fc9310f2ad
-F ext/fts5/test/fts5ac.test 5dea9e119ed39e0923b423dc2b3eaaef2ec3abd3
+F ext/fts5/test/fts5ac.test 1d2a10d4c13dcfd326287f51df3b7d90761c212c
F ext/fts5/test/fts5ad.test 0fd1a5bcb5dcc76a639bd26f27e2641034a508a3
F ext/fts5/test/fts5ae.test 0a9984fc3479f89f8c63d9848d6ed0c465dfcebe
F ext/fts5/test/fts5af.test c2501ec2b61d6b179c305f5d2b8782ab3d4f832a
F ext/fts5/test/fts5corrupt.test c2ad090192708150d50d961278df10ae7a4b8b62
F ext/fts5/test/fts5corrupt2.test 26c0a39dd9ff73207e6229f83b50b21d37c7658c
F ext/fts5/test/fts5corrupt3.test a2b537c120bdd43c79c42fe2438d7b8c81fe5599
-F ext/fts5/test/fts5detail.test 71babe633c68c6c5153b2fe1be81a97e953ca485 w ext/fts5/test/fts5offsets.test
+F ext/fts5/test/fts5detail.test 71babe633c68c6c5153b2fe1be81a97e953ca485
F ext/fts5/test/fts5dlidx.test ecba5e62ea8b26c33829961602069c546228046d
F ext/fts5/test/fts5doclist.test 8edb5b57e5f144030ed74ec00ef6fa4294fed79b
F ext/fts5/test/fts5ea.test b01e3a18cdfabbff8104a96a5242a06a68a998a0
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P 69bffc1632c8a8f3bfe5bf92607e64fed982e48c
-R bce3f221a6a9e036b503a3a5522049ea
+P 228b4d10e38f7d70e1b008c3c9b4a1ae3e32e30d
+R 9b7a210ea600814406fb8e0040363d54
U dan
-Z 73bb0a8c75a5e4585189e64532bdf9a9
+Z 50bb7fa01e78a4726d7b3d5426b2a1ed
-228b4d10e38f7d70e1b008c3c9b4a1ae3e32e30d
\ No newline at end of file
+8c30605bcd0a78a5015948171145bc6f640b8358
\ No newline at end of file