** i64 iRowid = sqlite3Fts5ExprRowid(pExpr);
** }
*/
-int sqlite3Fts5ExprFirst(Fts5Expr*, Fts5Index *pIdx, i64 iMin, int bDesc);
+int sqlite3Fts5ExprFirst(Fts5Expr*, Fts5Index *pIdx, i64 iMin, i64, int bDesc);
int sqlite3Fts5ExprNext(Fts5Expr*, i64 iMax);
int sqlite3Fts5ExprEof(Fts5Expr*);
i64 sqlite3Fts5ExprRowid(Fts5Expr*);
** Return SQLITE_OK if successful, or an SQLite error code otherwise. It
** is not considered an error if the query does not match any documents.
*/
-int sqlite3Fts5ExprFirst(Fts5Expr *p, Fts5Index *pIdx, i64 iFirst, int bDesc){
+int sqlite3Fts5ExprFirst(
+ Fts5Expr *p,
+ Fts5Index *pIdx,
+ i64 iFirst,
+ i64 iLast,
+ int bDesc
+){
Fts5ExprNode *pRoot = p->pRoot;
int rc; /* Return code */
assert( pRoot->bEof==0 );
rc = fts5ExprNodeNext(p, pRoot, 0, 0);
}
+ if( fts5RowidCmp(p, pRoot->iRowid, iLast)>0 ){
+ pRoot->bEof = 1;
+ }
return rc;
}
#endif
}
+static void fts5SetEstimatedRows(sqlite3_index_info *pIdxInfo, i64 nRow){
+#if SQLITE_VERSION_NUMBER>=3008002
+#ifndef SQLITE_CORE
+ if( sqlite3_libversion_number()>=3008002 )
+#endif
+ {
+ pIdxInfo->estimatedRows = nRow;
+ }
+#endif
+}
+
static int fts5UsePatternMatch(
Fts5Config *pConfig,
struct sqlite3_index_constraint *p
nSeenMatch++;
idxStr[iIdxStr++] = 'M';
sqlite3_snprintf(6, &idxStr[iIdxStr], "%d", iCol);
- idxStr += strlen(&idxStr[iIdxStr]);
+ iIdxStr += strlen(&idxStr[iIdxStr]);
assert( idxStr[iIdxStr]=='\0' );
}
pInfo->aConstraintUsage[i].argvIndex = ++iCons;
idxStr[iIdxStr++] = '=';
bSeenEq = 1;
pInfo->aConstraintUsage[i].argvIndex = ++iCons;
+ pInfo->aConstraintUsage[i].omit = 1;
}
}
}
/* Calculate the estimated cost based on the flags set in idxFlags. */
if( bSeenEq ){
- pInfo->estimatedCost = nSeenMatch ? 1000.0 : 10.0;
- if( nSeenMatch==0 ) fts5SetUniqueFlag(pInfo);
- }else if( bSeenLt && bSeenGt ){
- pInfo->estimatedCost = nSeenMatch ? 5000.0 : 250000.0;
- }else if( bSeenLt || bSeenGt ){
- pInfo->estimatedCost = nSeenMatch ? 7500.0 : 750000.0;
+ pInfo->estimatedCost = nSeenMatch ? 1000.0 : 25.0;
+ fts5SetUniqueFlag(pInfo);
+ fts5SetEstimatedRows(pInfo, 1);
}else{
- pInfo->estimatedCost = nSeenMatch ? 10000.0 : 1000000.0;
- }
- for(i=1; i<nSeenMatch; i++){
- pInfo->estimatedCost *= 0.4;
+ if( bSeenLt && bSeenGt ){
+ pInfo->estimatedCost = nSeenMatch ? 5000.0 : 750000.0;
+ }else if( bSeenLt || bSeenGt ){
+ pInfo->estimatedCost = nSeenMatch ? 7500.0 : 2250000.0;
+ }else{
+ pInfo->estimatedCost = nSeenMatch ? 10000.0 : 3000000.0;
+ }
+ for(i=1; i<nSeenMatch; i++){
+ pInfo->estimatedCost *= 0.4;
+ }
+ fts5SetEstimatedRows(pInfo, (i64)(pInfo->estimatedCost / 4.0));
}
pInfo->idxNum = idxFlags;
int bDesc = pCsr->bDesc;
i64 iRowid = sqlite3Fts5ExprRowid(pCsr->pExpr);
- rc = sqlite3Fts5ExprFirst(pCsr->pExpr, pTab->p.pIndex, iRowid, bDesc);
+ rc = sqlite3Fts5ExprFirst(
+ pCsr->pExpr, pTab->p.pIndex, iRowid, pCsr->iLastRowid, bDesc
+ );
if( rc==SQLITE_OK && iRowid!=sqlite3Fts5ExprRowid(pCsr->pExpr) ){
*pbSkip = 1;
}
static int fts5CursorFirst(Fts5FullTable *pTab, Fts5Cursor *pCsr, int bDesc){
int rc;
Fts5Expr *pExpr = pCsr->pExpr;
- rc = sqlite3Fts5ExprFirst(pExpr, pTab->p.pIndex, pCsr->iFirstRowid, bDesc);
+ rc = sqlite3Fts5ExprFirst(
+ pExpr, pTab->p.pIndex, pCsr->iFirstRowid, pCsr->iLastRowid, bDesc
+ );
if( sqlite3Fts5ExprEof(pExpr) ){
CsrFlagSet(pCsr, FTS5CSR_EOF);
}
--- /dev/null
+# 2014 June 17
+#
+# 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.
+#
+#*************************************************************************
+# This file implements regression tests for SQLite library. The
+# focus of this script is testing the FTS5 module.
+#
+
+source [file join [file dirname [info script]] fts5_common.tcl]
+set testprefix fts5join
+
+# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
+ifcapable !fts5 {
+ finish_test
+ return
+}
+
+do_execsql_test 1.0 {
+ CREATE VIRTUAL TABLE vt USING fts5(x);
+ INSERT INTO vt VALUES('abc');
+ INSERT INTO vt VALUES('xyz');
+
+ CREATE TABLE t1(a INTEGER PRIMARY KEY, b TIMESTAMP);
+ INSERT INTO t1 VALUES(1, 1), (2, 2);
+ CREATE INDEX i1 ON t1(b);
+}
+
+# set sqlite_where_trace [expr 0xFFF]
+
+do_eqp_test 1.1 {
+ SELECT * FROM vt, t1 WHERE vt.rowid = t1.rowid ORDER BY t1.rowid;
+} {
+ QUERY PLAN
+ |--SCAN t1
+ `--SCAN vt VIRTUAL TABLE INDEX 0:=
+}
+
+do_eqp_test 1.2 {
+ SELECT * FROM vt, t1 WHERE vt.rowid = t1.rowid AND b>? ORDER BY b LIMIT 10
+} {
+ QUERY PLAN
+ |--SEARCH t1 USING COVERING INDEX i1 (b>?)
+ `--SCAN vt VIRTUAL TABLE INDEX 0:=
+}
+
+do_eqp_test 1.3 {
+ SELECT * FROM vt, t1 WHERE vt.rowid = t1.rowid AND b>?
+} {
+ QUERY PLAN
+ |--SEARCH t1 USING COVERING INDEX i1 (b>?)
+ `--SCAN vt VIRTUAL TABLE INDEX 0:=
+}
+
+do_eqp_test 1.4 {
+ SELECT * FROM vt, t1 WHERE vt.rowid = t1.rowid ORDER BY b
+} {
+ QUERY PLAN
+ |--SCAN t1 USING COVERING INDEX i1
+ `--SCAN vt VIRTUAL TABLE INDEX 0:=
+}
+
+
+finish_test
COMMIT;
}
+#-------------------------------------------------------------------------
+reset_db
+
+do_execsql_test 27.0 {
+ CREATE VIRTUAL TABLE ft1 USING fts5(a, b);
+ INSERT INTO ft1(rowid, a, b) VALUES(3, '3', '3');
+}
+
+do_execsql_test 27.1 {
+ SELECT * FROM ft1 WHERE rowid=3 AND b MATCH 'hello';
+}
+
finish_test
1.2 { DELETE FROM ft WHERE rowid=? } 0
1.3 { DELETE FROM ft WHERE rowid=? } 0
1.4 { DELETE FROM ft WHERE ft MATCH '1' } 1
- 1.5 { DELETE FROM ft WHERE ft MATCH '1' AND rowid=? } 1
- 1.6 { DELETE FROM ft WHERE ft MATCH '1' AND rowid=? } 1
+ 1.5 { DELETE FROM ft WHERE ft MATCH '1' AND rowid=? } 0
+ 1.6 { DELETE FROM ft WHERE ft MATCH '1' AND rowid=? } 0
2.1 { UPDATE ft SET content='a b c' } 1
2.2 { UPDATE ft SET content='a b c' WHERE rowid=? } 0
2.3 { UPDATE ft SET content='a b c' WHERE rowid=? } 0
2.4 { UPDATE ft SET content='a b c' WHERE ft MATCH '1' } 1
- 2.5 { UPDATE ft SET content='a b c' WHERE ft MATCH '1' AND rowid=? } 1
- 2.6 { UPDATE ft SET content='a b c' WHERE ft MATCH '1' AND rowid=? } 1
+ 2.5 { UPDATE ft SET content='a b c' WHERE ft MATCH '1' AND rowid=? } 0
+ 2.6 { UPDATE ft SET content='a b c' WHERE ft MATCH '1' AND rowid=? } 0
} {
do_test 1.$tn { sql_uses_stmt db $sql } $uses
}
-C Fix\san\soff-by-one\serror\sin\ssqlite3_rsync.\n[forum:/info/46753431d4|Forum\spost\s46753431d4].
-D 2025-09-11T10:58:49.199
+C Updates\sto\swhere.c\sto\shandle\svtabs\sin\sjoins\smore\ssimilarly\sto\sregular\stables.
+D 2025-09-13T19:23:12.699
F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F ext/fts3/unicode/parseunicode.tcl a981bd6466d12dd17967515801c3ff23f74a281be1a03cf1e6f52a6959fc77eb
F ext/fts5/extract_api_docs.tcl 009cf59c77afa86d137b0cca3e3b1a5efbe2264faa2df233f9a7aa8563926d15
F ext/fts5/fts5.h ff5d3cc88b29e41612bfb29eb723e29e38973de62ca75ba3e8f94ccb67f5b5f2
-F ext/fts5/fts5Int.h 97f373ecedf024fa7bf23989c3e529132225c169e440fe1f48e9b28dfed05ddc
+F ext/fts5/fts5Int.h 4bba2aeadbbd7378675b1fd2967c377fba3147c9a836350c437844b590068927
F ext/fts5/fts5_aux.c da4a7a9a11ec15c6df0699d908915a209bcde48f0b04101461316b59f71abffb
F ext/fts5/fts5_buffer.c f1e6d0324d7c55329d340673befc26681a372a4d36086caa8d1ec7d7c53066c7
F ext/fts5/fts5_config.c e7d8dd062b44a66cd77e5a0f74f23a2354cd1f3f8575afb967b2773c3384f7f8
-F ext/fts5/fts5_expr.c be9e5f7f11d87e7bd3680832c93c13050fe351994b5052b0215c2ef40312c23a
+F ext/fts5/fts5_expr.c b8c32da1127bafaf10d6b4768b0dcb92285798524bed2d87a8686f99a8e8d259
F ext/fts5/fts5_hash.c a6266cedd801ab7964fa9e74ebcdda6d30ec6a96107fa24148ec6b7b5b80f6e0
F ext/fts5/fts5_index.c 2a1be0fb3c1b185f84b08b8032ba332c82defa182ff125833c0fecba0a4938b0
-F ext/fts5/fts5_main.c e558225168845dc708abeb2ad10415696e5a3249bcba1810ba3c7ef80764962e
+F ext/fts5/fts5_main.c a6f8bea608b5f5ffc06bd1407e188bb2284437e7dd0e96b492ff7f3df2c32347
F ext/fts5/fts5_storage.c 19bc7c4cbe1e6a2dd9849ef7d84b5ca1fcbf194cefc3e386b901e00e08bf05c2
F ext/fts5/fts5_tcl.c 7fb5a3d3404099075aaa2457307cb459bbc257c0de3dbd52b1e80a5b503e0329
F ext/fts5/fts5_test_mi.c 4308d5658cb1f5eee5998dcbaac7d5bdf7a2ef43c8192ca6e0c843f856ccee26
F ext/fts5/test/fts5integrity.test c423ce16fd1ccadcac7fc22f794226b2bb00f5a187c0ab1d9f8502521b1bae05
F ext/fts5/test/fts5integrity2.test 4c3636615c0201232c44a8105d5cb14fd5499fd0ee3014d7ffd7e83aac76ece8
F ext/fts5/test/fts5interrupt.test 20d04204d3e341b104c0c24a41596b6393a3a81eba1044c168db0e106f9ac92c
+F ext/fts5/test/fts5join.test 48b7ed36956948c5b8456c8bcaa5b087808d99000675918a43c4f51a925f1514
F ext/fts5/test/fts5lastrowid.test f36298a1fb9f988bde060a274a7ce638faa9c38a31400f8d2d27ea9373e0c4a1
F ext/fts5/test/fts5leftjoin.test 1c14b51f4d1344a89e488160882f05a2246dd7e70c5cf077c8fb473e03c66338
F ext/fts5/test/fts5limits.test 8ab67cf5d311c124b6ceb0062d0297767176df4572d955fce79fa43004dff01c
F ext/fts5/test/fts5matchinfo.test bc9e74157773db7f00aec1e85587f1145956ebdf1672c136f0f04323b2752aa0
F ext/fts5/test/fts5merge.test 2654df0bcdb2d117c2d38b6aeb0168061be01c643f9e9194b36c43a2970e8082
F ext/fts5/test/fts5merge2.test 3ebad1a59d6ad3fb66eff6523a09e95dc6367cbefb3cd73196801dea0425c8e2
-F ext/fts5/test/fts5misc.test f4dee7da898d605a6488c5b7afaace3158ed6bb9addff78faa1b37b402b77fb9
+F ext/fts5/test/fts5misc.test 83d6c5101a092c5db8fb631cfdd69a6482e20528b2750427641ac9050d9d0381
F ext/fts5/test/fts5multi.test a15bc91cdb717492e6e1b66fec1c356cb57386b980c7ba5af1915f97fe878581
F ext/fts5/test/fts5multiclient.test 5ff811c028d6108045ffef737f1e9f05028af2458e456c0937c1d1b8dea56d45
F ext/fts5/test/fts5near.test 33d60867581066e5db7016deb5d651628125d7ff4e0233a88175aa5b65874c74
-F ext/fts5/test/fts5onepass.test f9b7d9b2c334900c6542a869760290e2ab5382af8fbd618834bf1fcc3e7b84da
+F ext/fts5/test/fts5onepass.test b56d4109e841c2bc83555c162515748780ea6e0c455c54cf4afd4bd940d14b84
F ext/fts5/test/fts5optimize.test 264b9101721c17d06d1d174feb743fda3ddc89fad41dee980fef821428258e47
F ext/fts5/test/fts5optimize2.test 795d4ae5f66a7239cf8d5aef4c2ea96aeb8bcd907bd9be0cfe22064fc71a44ed
F ext/fts5/test/fts5optimize3.test 1653029284e10e0715246819893ba30565c4ead0d0fc470adae92c353ea857d3
F src/wal.c a278339ecf5f194fd71fff1f0da1368de50e3a32edc3e9944e1ee1f4610476ff
F src/wal.h ba252daaa94f889f4b2c17c027e823d9be47ce39da1d3799886bbd51f0490452
F src/walker.c d5006d6b005e4ea7302ad390957a8d41ed83faa177e412f89bc5600a7462a014
-F src/where.c f2f075bd17065922235632feb368efe92a7f03d42797eb575267574fbf6d4218
+F src/where.c 9d7b4095ae0a34d9604c3e185c65cdf6eca5f2e8707403c526eed798867cece4
F src/whereInt.h 8d94cb116c9e06205c3d5ac87af065fc044f8cf08bfdccd94b6ea1c1308e65da
F src/wherecode.c 71c5c6804b7f882dec8ec858758accae02fcfca13df3cc720f1f258e663ec7c5
F src/whereexpr.c 403a44eeec1a0f0914fccc6a59376b6924bc00ef6728fe6ffce4cf3051b320fc
F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7
F tool/warnings.sh 1ad0169b022b280bcaaf94a7fa231591be96b514230ab5c98fbf15cd7df842dd
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P 5bc6b9352236df3091ee69b947d0c397264156539d13e5968ec3b9a6e55dc800
-R a5539b6621653da7959fb888474ce821
-U drh
-Z 3cde64f623da7bc733a5eed51b57ab95
+P ef3b7be6f2037871f6f1b1944fed3dda28216e7f179080d3be2e2620c031f48c
+R 897d11ff33135df378e9ecdf2ba1caed
+T *branch * vtab-planner-fixes
+T *sym-vtab-planner-fixes *
+T -sym-trunk *
+U dan
+Z 99690642a15232d641aa4de8081ee700
# Remove this line to create a well-formed Fossil manifest.
-branch trunk
-tag trunk
+branch vtab-planner-fixes
+tag vtab-planner-fixes
-ef3b7be6f2037871f6f1b1944fed3dda28216e7f179080d3be2e2620c031f48c
+991383262b0d07ebc79fdb6bed448013cea3a0ac13292d5397dce012b1e6a673
&& ((wctrlFlags&(WHERE_DISTINCTBY|WHERE_SORTBYGROUP))!=WHERE_DISTINCTBY)
){
obSat = obDone;
+ }else{
+ /* No further ORDER BY terms may be matched. So this call should
+ ** return >=0, not -1. Clear isOrderDistinct to ensure it does so. */
+ isOrderDistinct = 0;
}
break;
}
for(i=0; i<pWInfo->nLevel; i++){
WhereLoop *p = pWInfo->a[i].pWLoop;
if( p==0 ) break;
- if( (p->wsFlags & WHERE_VIRTUALTABLE)!=0 ) continue;
+ if( (p->wsFlags & WHERE_VIRTUALTABLE)!=0 ){
+ /* Treat a vtab scan as similar to a full-table scan */
+ break;
+ }
if( (p->wsFlags & (WHERE_COLUMN_EQ|WHERE_COLUMN_NULL|WHERE_COLUMN_IN))!=0 ){
u8 iTab = p->iTab;
WhereLoop *pLoop;