1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-11-11 01:42:22 +03:00

Give the virtual table xBestIndex method access to (some) OFFSET and LIMIT

clauses.

FossilOrigin-Name: 74fa5757ee0a8499bcd6546dac1a3ecc6048ba9cff9e3e574e28e6e82e894a3d
This commit is contained in:
drh
2022-01-27 16:14:50 +00:00
parent 4b51e8bd68
commit 895bab3383
14 changed files with 174 additions and 35 deletions

View File

@@ -103,7 +103,8 @@ static const char *azColname[] = {
"ux", "ux",
"rhs", "rhs",
"a", "b", "c", "d", "e", "a", "b", "c", "d", "e",
"flags" "flags",
""
}; };
/* /*
@@ -143,6 +144,7 @@ static int qpvtabConnect(
#define QPVTAB_D 9 #define QPVTAB_D 9
#define QPVTAB_E 10 #define QPVTAB_E 10
#define QPVTAB_FLAGS 11 #define QPVTAB_FLAGS 11
#define QPVTAB_NONE 12
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
pNew = sqlite3_malloc( sizeof(*pNew) ); pNew = sqlite3_malloc( sizeof(*pNew) );
*ppVtab = (sqlite3_vtab*)pNew; *ppVtab = (sqlite3_vtab*)pNew;
@@ -338,6 +340,7 @@ static int qpvtabBestIndex(
for(i=0; i<pIdxInfo->nConstraint; i++){ for(i=0; i<pIdxInfo->nConstraint; i++){
sqlite3_value *pVal; sqlite3_value *pVal;
int iCol = pIdxInfo->aConstraint[i].iColumn; int iCol = pIdxInfo->aConstraint[i].iColumn;
int op = pIdxInfo->aConstraint[i].op;
if( iCol==QPVTAB_FLAGS && pIdxInfo->aConstraint[i].usable ){ if( iCol==QPVTAB_FLAGS && pIdxInfo->aConstraint[i].usable ){
pVal = 0; pVal = 0;
rc = sqlite3_vtab_rhs_value(pIdxInfo, i, &pVal); rc = sqlite3_vtab_rhs_value(pIdxInfo, i, &pVal);
@@ -347,10 +350,15 @@ static int qpvtabBestIndex(
if( pIdxInfo->idxNum & 2 ) pIdxInfo->orderByConsumed = 1; if( pIdxInfo->idxNum & 2 ) pIdxInfo->orderByConsumed = 1;
} }
} }
if( op==SQLITE_INDEX_CONSTRAINT_LIMIT
|| op==SQLITE_INDEX_CONSTRAINT_OFFSET
){
iCol = QPVTAB_NONE;
}
sqlite3_str_appendf(pStr,"aConstraint,%d,%s,%d,%d,", sqlite3_str_appendf(pStr,"aConstraint,%d,%s,%d,%d,",
i, i,
azColname[iCol], azColname[iCol],
pIdxInfo->aConstraint[i].op, op,
pIdxInfo->aConstraint[i].usable); pIdxInfo->aConstraint[i].usable);
pVal = 0; pVal = 0;
rc = sqlite3_vtab_rhs_value(pIdxInfo, i, &pVal); rc = sqlite3_vtab_rhs_value(pIdxInfo, i, &pVal);

View File

@@ -1,5 +1,5 @@
C Enforce\sthe\srestriction\sthat\s'unixepoch'\sonly\sworks\sas\sthe\sfirst\smodifier\nafter\sthe\stime-value.\s\sThis\shas\sbeen\sdocumented\ssince\s2004,\sbut\shas\snever\nactually\sbeen\senforced\sbefore.\s\sAlso\sadd\snew\stest\scases\sfor\sdate/time\nfunctions\swith\sevidence\smarks. C Give\sthe\svirtual\stable\sxBestIndex\smethod\saccess\sto\s(some)\sOFFSET\sand\sLIMIT\nclauses.
D 2022-01-27T13:52:01.555 D 2022-01-27T16:14:50.962
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -316,7 +316,7 @@ F ext/misc/noop.c 81efe4cad9ec740e64388b14281cb983e6e2c223fed43eb77ab3e34946e0c1
F ext/misc/normalize.c bd84355c118e297522aba74de34a4fd286fc775524e0499b14473918d09ea61f F ext/misc/normalize.c bd84355c118e297522aba74de34a4fd286fc775524e0499b14473918d09ea61f
F ext/misc/percentile.c b9086e223d583bdaf8cb73c98a6539d501a2fc4282654adbfea576453d82e691 F ext/misc/percentile.c b9086e223d583bdaf8cb73c98a6539d501a2fc4282654adbfea576453d82e691
F ext/misc/prefixes.c 0f4f8cff5aebc00a7e3ac4021fd59cfe1a8e17c800ceaf592859ecb9cbc38196 F ext/misc/prefixes.c 0f4f8cff5aebc00a7e3ac4021fd59cfe1a8e17c800ceaf592859ecb9cbc38196
F ext/misc/qpvtab.c c662fa0a452ad286e49b6c83ac917600656b2eb47d2225ff6185c56bf80cf8d2 F ext/misc/qpvtab.c 03986dca441274933dd924170ceee50ad248d24a4cd6a686ff45d5e65e5deac4
F ext/misc/regexp.c b267fd05ff8d38b22f4c2809d7b7a2c61d522e9faf2feb928dbb9662e4a3a386 F ext/misc/regexp.c b267fd05ff8d38b22f4c2809d7b7a2c61d522e9faf2feb928dbb9662e4a3a386
F ext/misc/remember.c add730f0f7e7436cd15ea3fd6a90fd83c3f706ab44169f7f048438b7d6baa69c F ext/misc/remember.c add730f0f7e7436cd15ea3fd6a90fd83c3f706ab44169f7f048438b7d6baa69c
F ext/misc/rot13.c 51ac5f51e9d5fd811db58a9c23c628ad5f333c173f1fc53c8491a3603d38556c F ext/misc/rot13.c 51ac5f51e9d5fd811db58a9c23c628ad5f333c173f1fc53c8491a3603d38556c
@@ -502,10 +502,10 @@ F src/ctime.c 2cce39df1a13e05b7633e6d21b651f21492471f991dd7b323a4ee4e7b7f0b7f1
F src/date.c 41627dec396f3d33e2c317a065f9d59bb535982b2ea3a561c96e4d4cf1137b65 F src/date.c 41627dec396f3d33e2c317a065f9d59bb535982b2ea3a561c96e4d4cf1137b65
F src/dbpage.c 8a01e865bf8bc6d7b1844b4314443a6436c07c3efe1d488ed89e81719047833a F src/dbpage.c 8a01e865bf8bc6d7b1844b4314443a6436c07c3efe1d488ed89e81719047833a
F src/dbstat.c 861e08690fcb0f2ee1165eff0060ea8d4f3e2ea10f80dab7d32ad70443a6ff2d F src/dbstat.c 861e08690fcb0f2ee1165eff0060ea8d4f3e2ea10f80dab7d32ad70443a6ff2d
F src/delete.c 52897a8516dc40753503c25eed0e305f09cc50ae474f22b0b4fd31d3b879cc08 F src/delete.c b5f1716b4d723db48254ee0f896e362cd029e865e05414139ea7f539f3884e1d
F src/expr.c 9658bccd1598211ace848c8ca9480dbf8be08dfee1db5cf03897b34b7b6e8fef F src/expr.c 9658bccd1598211ace848c8ca9480dbf8be08dfee1db5cf03897b34b7b6e8fef
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007 F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
F src/fkey.c 5b73f7a7c00f06017531a5bd258cbc2c7a294e55a7f84a729fe27aa525242560 F src/fkey.c 06e4ac33031b02dde7130c12e79cddf4dc5cfa72b23d8e63a3c26878fc9c1d3c
F src/func.c 8fddc42bce95d17938252a543f86fe29e479366e80fbd112a1822913b6247776 F src/func.c 8fddc42bce95d17938252a543f86fe29e479366e80fbd112a1822913b6247776
F src/global.c 1f56aead86e8a18c4415638f5e6c4d0a0550427f4b3f5d065ba5164cc09c22e8 F src/global.c 1f56aead86e8a18c4415638f5e6c4d0a0550427f4b3f5d065ba5164cc09c22e8
F src/hash.c 8d7dda241d0ebdafb6ffdeda3149a412d7df75102cecfc1021c98d6219823b19 F src/hash.c 8d7dda241d0ebdafb6ffdeda3149a412d7df75102cecfc1021c98d6219823b19
@@ -552,12 +552,12 @@ F src/printf.c 975f1f5417f2526365b6e6d7f22332e3e11806dad844701d92846292b654ba9a
F src/random.c 097dc8b31b8fba5a9aca1697aeb9fd82078ec91be734c16bffda620ced7ab83c F src/random.c 097dc8b31b8fba5a9aca1697aeb9fd82078ec91be734c16bffda620ced7ab83c
F src/resolve.c 24032ae57aec10df2f3fa2e20be0aae7d256bc704124b76c52d763440c7c0fe9 F src/resolve.c 24032ae57aec10df2f3fa2e20be0aae7d256bc704124b76c52d763440c7c0fe9
F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92 F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92
F src/select.c 5799f5b15e27bcb8262caec7821f3ef89575e539237db3141be0d26cf8efd22c F src/select.c a6d2d4bed279d7fe4fcedaf297eaf6441e8e17c6e3947a32d24d23be52ac02f2
F src/shell.c.in e80a140e92e342e2f92d405a77155c8e3a67c9b1d0bdbacb92885960cd4fc8f2 F src/shell.c.in e80a140e92e342e2f92d405a77155c8e3a67c9b1d0bdbacb92885960cd4fc8f2
F src/sqlite.h.in 31c2c8d737814369bd3b71f3849c4a97ef7ede0aa3ce976ecb11632fa5f1f863 F src/sqlite.h.in da0e94f140f3f054f0eca8fc4a183167bedc7ae9c51822390c62369455eae5f8
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h 5d54cf13d3406d8eb65d921a0d3c349de6126b732e695e79ecd4830ce86b4f8a F src/sqlite3ext.h 5d54cf13d3406d8eb65d921a0d3c349de6126b732e695e79ecd4830ce86b4f8a
F src/sqliteInt.h 33fbafb55b48f63b791c563378345ebdbbcb73e8fd63a1c22e4df05f435d4714 F src/sqliteInt.h 8ef2996e02476f73e41ba977f819bda0cc68b7ce238cf404b9b8930df57bc1d0
F src/sqliteLimit.h d7323ffea5208c6af2734574bae933ca8ed2ab728083caa117c9738581a31657 F src/sqliteLimit.h d7323ffea5208c6af2734574bae933ca8ed2ab728083caa117c9738581a31657
F src/status.c 4b8bc2a6905163a38b739854a35b826c737333fab5b1f8e03fa7eb9a4799c4c1 F src/status.c 4b8bc2a6905163a38b739854a35b826c737333fab5b1f8e03fa7eb9a4799c4c1
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
@@ -574,7 +574,7 @@ F src/test9.c 12e5ba554d2d1cbe0158f6ab3f7ffcd7a86ee4e5
F src/test_async.c 195ab49da082053fdb0f949c114b806a49ca770a F src/test_async.c 195ab49da082053fdb0f949c114b806a49ca770a
F src/test_autoext.c 915d245e736652a219a907909bb6710f0d587871 F src/test_autoext.c 915d245e736652a219a907909bb6710f0d587871
F src/test_backup.c bf5da90c9926df0a4b941f2d92825a01bbe090a0 F src/test_backup.c bf5da90c9926df0a4b941f2d92825a01bbe090a0
F src/test_bestindex.c 78809f11026f18a93fcfd798d9479cba37e1201c830260bf1edc674b2fa9b857 F src/test_bestindex.c ba0314d3bca8b00fa0daaf113a314986f73ea8ad85a7562f983638d09a29045c
F src/test_blob.c ae4a0620b478548afb67963095a7417cd06a4ec0a56adb453542203bfdcb31ce F src/test_blob.c ae4a0620b478548afb67963095a7417cd06a4ec0a56adb453542203bfdcb31ce
F src/test_btree.c 8b2dc8b8848cf3a4db93f11578f075e82252a274 F src/test_btree.c 8b2dc8b8848cf3a4db93f11578f075e82252a274
F src/test_config.c 284c29912736f68b0a583a920bf63fd8f9125dffb8a75cb0676e58502b2f7908 F src/test_config.c 284c29912736f68b0a583a920bf63fd8f9125dffb8a75cb0676e58502b2f7908
@@ -619,7 +619,7 @@ F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c
F src/tokenize.c b74d878aa7c82ec8460779468061a96185e22257f68ab785b69abce354b70446 F src/tokenize.c b74d878aa7c82ec8460779468061a96185e22257f68ab785b69abce354b70446
F src/treeview.c 9dfdb7ff7f6645d0a6458dbdf4ffac041c071c4533a6db8bb6e502b979ac67bc F src/treeview.c 9dfdb7ff7f6645d0a6458dbdf4ffac041c071c4533a6db8bb6e502b979ac67bc
F src/trigger.c 692972e4393dfc8017a1a527c1ea1b96ce3d101e84584cd832fcfb83d22b50b2 F src/trigger.c 692972e4393dfc8017a1a527c1ea1b96ce3d101e84584cd832fcfb83d22b50b2
F src/update.c 7dfa3866cdfb28bf952c38054c1722720d8ff64750dea421790aecc91f640516 F src/update.c f875b0d59da5c3055a0b2ac20560e1650229c6787e78de5e9836267b5cbb8359
F src/upsert.c 8789047a8f0a601ea42fa0256d1ba3190c13746b6ba940fe2d25643a7e991937 F src/upsert.c 8789047a8f0a601ea42fa0256d1ba3190c13746b6ba940fe2d25643a7e991937
F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0 F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0
F src/util.c 602fe229f32a96ceccae4f40824129669582096f7c355f53dbac156c9fecef23 F src/util.c 602fe229f32a96ceccae4f40824129669582096f7c355f53dbac156c9fecef23
@@ -639,10 +639,10 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
F src/wal.c b9df133a705093da8977da5eb202eaadb844839f1c7297c08d33471f5491843d F src/wal.c b9df133a705093da8977da5eb202eaadb844839f1c7297c08d33471f5491843d
F src/wal.h c3aa7825bfa2fe0d85bef2db94655f99870a285778baa36307c0a16da32b226a F src/wal.h c3aa7825bfa2fe0d85bef2db94655f99870a285778baa36307c0a16da32b226a
F src/walker.c f890a3298418d7cba3b69b8803594fdc484ea241206a8dfa99db6dd36f8cbb3b F src/walker.c f890a3298418d7cba3b69b8803594fdc484ea241206a8dfa99db6dd36f8cbb3b
F src/where.c a14990c7b35e95f8f9cb0dc0d6d2e32fa99135a716a04027cefa48138d280ecb F src/where.c f89c21296cdf23bbc73333c77a01e0bfdccc9d1a767d38a145e3a8658456b66c
F src/whereInt.h 8a215acde0f833a4dea3d30a7bbed9f48b4b547b5d5e34cd02acee366476ab80 F src/whereInt.h e23780eb06810dc8bd7d855c97a667bf116cb929d8aa107ce1db91df8e47aaa8
F src/wherecode.c 8da0f873278ed6aad42bf2028404d7178dd9cfcdc7179ecc61a87591a15a07d2 F src/wherecode.c 37878a0a6f790b77f41e7b3d77c42f14bded09aef3d363eaf19b3ee02e765666
F src/whereexpr.c 9f64c39e53070584e99e4d20c1dd3397e125fabbae8fd414ffec574c410ac7d3 F src/whereexpr.c 50b09b3583301d0a5aef0e5b5d225f4d2b0eba2e36e3f9d0b914e110d4b2f6ce
F src/window.c dfaec4abc6012cbc18e4a202ca3a5d5a0efcc4011d86a06d882ddaab8aedee4d F src/window.c dfaec4abc6012cbc18e4a202ca3a5d5a0efcc4011d86a06d882ddaab8aedee4d
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
F test/affinity2.test ce1aafc86e110685b324e9a763eab4f2a73f737842ec3b687bd965867de90627 F test/affinity2.test ce1aafc86e110685b324e9a763eab4f2a73f737842ec3b687bd965867de90627
@@ -1942,8 +1942,11 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
P a8db69411b0d1275909adeb21027784ada17af24efe3a59ae0ae2a897659ff17 P 64fa9e8c87179211cec248e6dfd7578502e6e969a19e91a4f0e21ed9b972a6bc
R a92b0ae1c265a80dc4f7e5c12c916bf4 R c3554501c3177117c353a66ed5c4eb7c
T *branch * vtab-limit-offset
T *sym-vtab-limit-offset *
T -sym-trunk *
U drh U drh
Z 47b9e1bb1e6a61a53486ee72f7ca6190 Z 853246eb39d3c5347b902f7c653bc6b9
# Remove this line to create a well-formed Fossil manifest. # Remove this line to create a well-formed Fossil manifest.

View File

@@ -1 +1 @@
64fa9e8c87179211cec248e6dfd7578502e6e969a19e91a4f0e21ed9b972a6bc 74fa5757ee0a8499bcd6546dac1a3ecc6048ba9cff9e3e574e28e6e82e894a3d

View File

@@ -478,7 +478,7 @@ void sqlite3DeleteFrom(
** ONEPASS_SINGLE: One-pass approach - at most one row deleted. ** ONEPASS_SINGLE: One-pass approach - at most one row deleted.
** ONEPASS_MULTI: One-pass approach - any number of rows may be deleted. ** ONEPASS_MULTI: One-pass approach - any number of rows may be deleted.
*/ */
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, 0, wcf, iTabCur+1); pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, 0,0,wcf,iTabCur+1);
if( pWInfo==0 ) goto delete_from_cleanup; if( pWInfo==0 ) goto delete_from_cleanup;
eOnePass = sqlite3WhereOkOnePass(pWInfo, aiCurOnePass); eOnePass = sqlite3WhereOkOnePass(pWInfo, aiCurOnePass);
assert( IsVirtual(pTab)==0 || eOnePass!=ONEPASS_MULTI ); assert( IsVirtual(pTab)==0 || eOnePass!=ONEPASS_MULTI );

View File

@@ -651,7 +651,7 @@ static void fkScanChildren(
** clause. For each row found, increment either the deferred or immediate ** clause. For each row found, increment either the deferred or immediate
** foreign key constraint counter. */ ** foreign key constraint counter. */
if( pParse->nErr==0 ){ if( pParse->nErr==0 ){
pWInfo = sqlite3WhereBegin(pParse, pSrc, pWhere, 0, 0, 0, 0); pWInfo = sqlite3WhereBegin(pParse, pSrc, pWhere, 0, 0, 0, 0, 0);
sqlite3VdbeAddOp2(v, OP_FkCounter, pFKey->isDeferred, nIncr); sqlite3VdbeAddOp2(v, OP_FkCounter, pFKey->isDeferred, nIncr);
if( pWInfo ){ if( pWInfo ){
sqlite3WhereEnd(pWInfo); sqlite3WhereEnd(pWInfo);

View File

@@ -6898,7 +6898,7 @@ int sqlite3Select(
/* Begin the database scan. */ /* Begin the database scan. */
SELECTTRACE(1,pParse,p,("WhereBegin\n")); SELECTTRACE(1,pParse,p,("WhereBegin\n"));
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, sSort.pOrderBy, pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, sSort.pOrderBy,
p->pEList, wctrlFlags, p->nSelectRow); p->pEList, p, wctrlFlags, p->nSelectRow);
if( pWInfo==0 ) goto select_end; if( pWInfo==0 ) goto select_end;
if( sqlite3WhereOutputRowCount(pWInfo) < p->nSelectRow ){ if( sqlite3WhereOutputRowCount(pWInfo) < p->nSelectRow ){
p->nSelectRow = sqlite3WhereOutputRowCount(pWInfo); p->nSelectRow = sqlite3WhereOutputRowCount(pWInfo);
@@ -7162,7 +7162,7 @@ int sqlite3Select(
sqlite3VdbeAddOp2(v, OP_Gosub, regReset, addrReset); sqlite3VdbeAddOp2(v, OP_Gosub, regReset, addrReset);
SELECTTRACE(1,pParse,p,("WhereBegin\n")); SELECTTRACE(1,pParse,p,("WhereBegin\n"));
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pGroupBy, pDistinct, pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pGroupBy, pDistinct,
WHERE_GROUPBY | (orderByGrp ? WHERE_SORTBYGROUP : 0) | distFlag, 0 0, (WHERE_GROUPBY|(orderByGrp ? WHERE_SORTBYGROUP : 0)|distFlag), 0
); );
if( pWInfo==0 ){ if( pWInfo==0 ){
sqlite3ExprListDelete(db, pDistinct); sqlite3ExprListDelete(db, pDistinct);
@@ -7460,7 +7460,7 @@ int sqlite3Select(
SELECTTRACE(1,pParse,p,("WhereBegin\n")); SELECTTRACE(1,pParse,p,("WhereBegin\n"));
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pMinMaxOrderBy, pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pMinMaxOrderBy,
pDistinct, minMaxFlag|distFlag, 0); pDistinct, 0, minMaxFlag|distFlag, 0);
if( pWInfo==0 ){ if( pWInfo==0 ){
goto select_end; goto select_end;
} }

View File

@@ -7148,6 +7148,8 @@ struct sqlite3_index_info {
#define SQLITE_INDEX_CONSTRAINT_ISNOTNULL 70 #define SQLITE_INDEX_CONSTRAINT_ISNOTNULL 70
#define SQLITE_INDEX_CONSTRAINT_ISNULL 71 #define SQLITE_INDEX_CONSTRAINT_ISNULL 71
#define SQLITE_INDEX_CONSTRAINT_IS 72 #define SQLITE_INDEX_CONSTRAINT_IS 72
#define SQLITE_INDEX_CONSTRAINT_LIMIT 73
#define SQLITE_INDEX_CONSTRAINT_OFFSET 74
#define SQLITE_INDEX_CONSTRAINT_FUNCTION 150 #define SQLITE_INDEX_CONSTRAINT_FUNCTION 150
/* /*

View File

@@ -4577,7 +4577,8 @@ void sqlite3CodeChangeCount(Vdbe*,int,const char*);
void sqlite3DeleteFrom(Parse*, SrcList*, Expr*, ExprList*, Expr*); void sqlite3DeleteFrom(Parse*, SrcList*, Expr*, ExprList*, Expr*);
void sqlite3Update(Parse*, SrcList*, ExprList*,Expr*,int,ExprList*,Expr*, void sqlite3Update(Parse*, SrcList*, ExprList*,Expr*,int,ExprList*,Expr*,
Upsert*); Upsert*);
WhereInfo *sqlite3WhereBegin(Parse*,SrcList*,Expr*,ExprList*,ExprList*,u16,int); WhereInfo *sqlite3WhereBegin(Parse*,SrcList*,Expr*,ExprList*,
ExprList*,Select*,u16,int);
void sqlite3WhereEnd(WhereInfo*); void sqlite3WhereEnd(WhereInfo*);
LogEst sqlite3WhereOutputRowCount(WhereInfo*); LogEst sqlite3WhereOutputRowCount(WhereInfo*);
int sqlite3WhereIsDistinct(WhereInfo*); int sqlite3WhereIsDistinct(WhereInfo*);

View File

@@ -424,6 +424,10 @@ static int tclBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
zOp = "isnull"; break; zOp = "isnull"; break;
case SQLITE_INDEX_CONSTRAINT_IS: case SQLITE_INDEX_CONSTRAINT_IS:
zOp = "is"; break; zOp = "is"; break;
case SQLITE_INDEX_CONSTRAINT_LIMIT:
zOp = "limit"; break;
case SQLITE_INDEX_CONSTRAINT_OFFSET:
zOp = "offset"; break;
} }
Tcl_ListObjAppendElement(0, pElem, Tcl_NewStringObj("op", -1)); Tcl_ListObjAppendElement(0, pElem, Tcl_NewStringObj("op", -1));

View File

@@ -723,7 +723,7 @@ void sqlite3Update(
if( !pParse->nested && !pTrigger && !hasFK && !chngKey && !bReplace ){ if( !pParse->nested && !pTrigger && !hasFK && !chngKey && !bReplace ){
flags |= WHERE_ONEPASS_MULTIROW; flags |= WHERE_ONEPASS_MULTIROW;
} }
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, 0, flags,iIdxCur); pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere,0,0,0,flags,iIdxCur);
if( pWInfo==0 ) goto update_cleanup; if( pWInfo==0 ) goto update_cleanup;
/* A one-pass strategy that might update more than one row may not /* A one-pass strategy that might update more than one row may not
@@ -1245,7 +1245,9 @@ static void updateVirtualTable(
regRowid = ++pParse->nMem; regRowid = ++pParse->nMem;
/* Start scanning the virtual table */ /* Start scanning the virtual table */
pWInfo = sqlite3WhereBegin(pParse, pSrc,pWhere,0,0,WHERE_ONEPASS_DESIRED,0); pWInfo = sqlite3WhereBegin(
pParse, pSrc, pWhere, 0, 0, 0, WHERE_ONEPASS_DESIRED, 0
);
if( pWInfo==0 ) return; if( pWInfo==0 ) return;
/* Populate the argument registers. */ /* Populate the argument registers. */

View File

@@ -3459,6 +3459,16 @@ static int whereLoopAddBtree(
#ifndef SQLITE_OMIT_VIRTUALTABLE #ifndef SQLITE_OMIT_VIRTUALTABLE
/*
** Return true if pTerm is a virtual table LIMIT or OFFSET term.
*/
static int isLimitTerm(WhereTerm *pTerm){
return pTerm->eOperator==WO_AUX && (
pTerm->eMatchOp==SQLITE_INDEX_CONSTRAINT_LIMIT
|| pTerm->eMatchOp==SQLITE_INDEX_CONSTRAINT_OFFSET
);
}
/* /*
** Argument pIdxInfo is already populated with all constraints that may ** Argument pIdxInfo is already populated with all constraints that may
** be used by the virtual table identified by pBuilder->pNew->iTab. This ** be used by the virtual table identified by pBuilder->pNew->iTab. This
@@ -3486,7 +3496,8 @@ static int whereLoopAddVirtualOne(
u16 mExclude, /* Exclude terms using these operators */ u16 mExclude, /* Exclude terms using these operators */
sqlite3_index_info *pIdxInfo, /* Populated object for xBestIndex */ sqlite3_index_info *pIdxInfo, /* Populated object for xBestIndex */
u16 mNoOmit, /* Do not omit these constraints */ u16 mNoOmit, /* Do not omit these constraints */
int *pbIn /* OUT: True if plan uses an IN(...) op */ int *pbIn, /* OUT: True if plan uses an IN(...) op */
int *pbRetryLimit /* OUT: Retry without LIMIT/OFFSET */
){ ){
WhereClause *pWC = pBuilder->pWC; WhereClause *pWC = pBuilder->pWC;
struct sqlite3_index_constraint *pIdxCons; struct sqlite3_index_constraint *pIdxCons;
@@ -3511,6 +3522,7 @@ static int whereLoopAddVirtualOne(
pIdxCons->usable = 0; pIdxCons->usable = 0;
if( (pTerm->prereqRight & mUsable)==pTerm->prereqRight if( (pTerm->prereqRight & mUsable)==pTerm->prereqRight
&& (pTerm->eOperator & mExclude)==0 && (pTerm->eOperator & mExclude)==0
&& (pbRetryLimit || !isLimitTerm(pTerm))
){ ){
pIdxCons->usable = 1; pIdxCons->usable = 1;
} }
@@ -3589,6 +3601,21 @@ static int whereLoopAddVirtualOne(
pIdxInfo->idxFlags &= ~SQLITE_INDEX_SCAN_UNIQUE; pIdxInfo->idxFlags &= ~SQLITE_INDEX_SCAN_UNIQUE;
*pbIn = 1; assert( (mExclude & WO_IN)==0 ); *pbIn = 1; assert( (mExclude & WO_IN)==0 );
} }
if( isLimitTerm(pTerm) && *pbIn ){
/* If there is an IN(...) term handled as an == (separate call to
** xFilter for each value on the RHS of the IN) and a LIMIT or
** OFFSET term handled as well, the plan is unusable. Set output
** variable *pbRetryLimit to true to tell the caller to retry with
** LIMIT and OFFSET disabled. */
if( pIdxInfo->needToFreeIdxStr ){
sqlite3_free(pIdxInfo->idxStr);
pIdxInfo->idxStr = 0;
pIdxInfo->needToFreeIdxStr = 0;
}
*pbRetryLimit = 1;
return SQLITE_OK;
}
} }
} }
@@ -3751,6 +3778,7 @@ static int whereLoopAddVirtual(
WhereLoop *pNew; WhereLoop *pNew;
Bitmask mBest; /* Tables used by best possible plan */ Bitmask mBest; /* Tables used by best possible plan */
u16 mNoOmit; u16 mNoOmit;
int bRetry = 0; /* True to retry with LIMIT/OFFSET disabled */
assert( (mPrereq & mUnusable)==0 ); assert( (mPrereq & mUnusable)==0 );
pWInfo = pBuilder->pWInfo; pWInfo = pBuilder->pWInfo;
@@ -3774,7 +3802,15 @@ static int whereLoopAddVirtual(
/* First call xBestIndex() with all constraints usable. */ /* First call xBestIndex() with all constraints usable. */
WHERETRACE(0x800, ("BEGIN %s.addVirtual()\n", pSrc->pTab->zName)); WHERETRACE(0x800, ("BEGIN %s.addVirtual()\n", pSrc->pTab->zName));
WHERETRACE(0x40, (" VirtualOne: all usable\n")); WHERETRACE(0x40, (" VirtualOne: all usable\n"));
rc = whereLoopAddVirtualOne(pBuilder, mPrereq, ALLBITS, 0, p, mNoOmit, &bIn); rc = whereLoopAddVirtualOne(
pBuilder, mPrereq, ALLBITS, 0, p, mNoOmit, &bIn, &bRetry
);
if( bRetry ){
assert( rc==SQLITE_OK );
rc = whereLoopAddVirtualOne(
pBuilder, mPrereq, ALLBITS, 0, p, mNoOmit, &bIn, 0
);
}
/* If the call to xBestIndex() with all terms enabled produced a plan /* If the call to xBestIndex() with all terms enabled produced a plan
** that does not require any source tables (IOW: a plan with mBest==0) ** that does not require any source tables (IOW: a plan with mBest==0)
@@ -3792,7 +3828,7 @@ static int whereLoopAddVirtual(
if( bIn ){ if( bIn ){
WHERETRACE(0x40, (" VirtualOne: all usable w/o IN\n")); WHERETRACE(0x40, (" VirtualOne: all usable w/o IN\n"));
rc = whereLoopAddVirtualOne( rc = whereLoopAddVirtualOne(
pBuilder, mPrereq, ALLBITS, WO_IN, p, mNoOmit, &bIn); pBuilder, mPrereq, ALLBITS, WO_IN, p, mNoOmit, &bIn, 0);
assert( bIn==0 ); assert( bIn==0 );
mBestNoIn = pNew->prereq & ~mPrereq; mBestNoIn = pNew->prereq & ~mPrereq;
if( mBestNoIn==0 ){ if( mBestNoIn==0 ){
@@ -3819,7 +3855,7 @@ static int whereLoopAddVirtual(
WHERETRACE(0x40, (" VirtualOne: mPrev=%04llx mNext=%04llx\n", WHERETRACE(0x40, (" VirtualOne: mPrev=%04llx mNext=%04llx\n",
(sqlite3_uint64)mPrev, (sqlite3_uint64)mNext)); (sqlite3_uint64)mPrev, (sqlite3_uint64)mNext));
rc = whereLoopAddVirtualOne( rc = whereLoopAddVirtualOne(
pBuilder, mPrereq, mNext|mPrereq, 0, p, mNoOmit, &bIn); pBuilder, mPrereq, mNext|mPrereq, 0, p, mNoOmit, &bIn, 0);
if( pNew->prereq==mPrereq ){ if( pNew->prereq==mPrereq ){
seenZero = 1; seenZero = 1;
if( bIn==0 ) seenZeroNoIN = 1; if( bIn==0 ) seenZeroNoIN = 1;
@@ -3832,7 +3868,7 @@ static int whereLoopAddVirtual(
if( rc==SQLITE_OK && seenZero==0 ){ if( rc==SQLITE_OK && seenZero==0 ){
WHERETRACE(0x40, (" VirtualOne: all disabled\n")); WHERETRACE(0x40, (" VirtualOne: all disabled\n"));
rc = whereLoopAddVirtualOne( rc = whereLoopAddVirtualOne(
pBuilder, mPrereq, mPrereq, 0, p, mNoOmit, &bIn); pBuilder, mPrereq, mPrereq, 0, p, mNoOmit, &bIn, 0);
if( bIn==0 ) seenZeroNoIN = 1; if( bIn==0 ) seenZeroNoIN = 1;
} }
@@ -3842,7 +3878,7 @@ static int whereLoopAddVirtual(
if( rc==SQLITE_OK && seenZeroNoIN==0 ){ if( rc==SQLITE_OK && seenZeroNoIN==0 ){
WHERETRACE(0x40, (" VirtualOne: all disabled and w/o IN\n")); WHERETRACE(0x40, (" VirtualOne: all disabled and w/o IN\n"));
rc = whereLoopAddVirtualOne( rc = whereLoopAddVirtualOne(
pBuilder, mPrereq, mPrereq, WO_IN, p, mNoOmit, &bIn); pBuilder, mPrereq, mPrereq, WO_IN, p, mNoOmit, &bIn, 0);
} }
} }
@@ -5248,6 +5284,7 @@ WhereInfo *sqlite3WhereBegin(
Expr *pWhere, /* The WHERE clause */ Expr *pWhere, /* The WHERE clause */
ExprList *pOrderBy, /* An ORDER BY (or GROUP BY) clause, or NULL */ ExprList *pOrderBy, /* An ORDER BY (or GROUP BY) clause, or NULL */
ExprList *pResultSet, /* Query result set. Req'd for DISTINCT */ ExprList *pResultSet, /* Query result set. Req'd for DISTINCT */
Select *pLimit, /* Use this LIMIT/OFFSET clause, if any */
u16 wctrlFlags, /* The WHERE_* flags defined in sqliteInt.h */ u16 wctrlFlags, /* The WHERE_* flags defined in sqliteInt.h */
int iAuxArg /* If WHERE_OR_SUBCLAUSE is set, index cursor number int iAuxArg /* If WHERE_OR_SUBCLAUSE is set, index cursor number
** If WHERE_USE_LIMIT, then the limit amount */ ** If WHERE_USE_LIMIT, then the limit amount */
@@ -5324,6 +5361,9 @@ WhereInfo *sqlite3WhereBegin(
pWInfo->wctrlFlags = wctrlFlags; pWInfo->wctrlFlags = wctrlFlags;
pWInfo->iLimit = iAuxArg; pWInfo->iLimit = iAuxArg;
pWInfo->savedNQueryLoop = pParse->nQueryLoop; pWInfo->savedNQueryLoop = pParse->nQueryLoop;
#ifndef SQLITE_OMIT_VIRTUALTABLE
pWInfo->pLimit = pLimit;
#endif
memset(&pWInfo->nOBSat, 0, memset(&pWInfo->nOBSat, 0,
offsetof(WhereInfo,sWC) - offsetof(WhereInfo,nOBSat)); offsetof(WhereInfo,sWC) - offsetof(WhereInfo,nOBSat));
memset(&pWInfo->a[0], 0, sizeof(WhereLoop)+nTabList*sizeof(WhereLevel)); memset(&pWInfo->a[0], 0, sizeof(WhereLoop)+nTabList*sizeof(WhereLevel));
@@ -5392,6 +5432,7 @@ WhereInfo *sqlite3WhereBegin(
/* Analyze all of the subexpressions. */ /* Analyze all of the subexpressions. */
sqlite3WhereExprAnalyze(pTabList, &pWInfo->sWC); sqlite3WhereExprAnalyze(pTabList, &pWInfo->sWC);
sqlite3WhereAddLimit(&pWInfo->sWC, pLimit);
if( db->mallocFailed ) goto whereBeginError; if( db->mallocFailed ) goto whereBeginError;
/* Special case: WHERE terms that do not refer to any tables in the join /* Special case: WHERE terms that do not refer to any tables in the join

View File

@@ -453,6 +453,9 @@ struct WhereInfo {
ExprList *pOrderBy; /* The ORDER BY clause or NULL */ ExprList *pOrderBy; /* The ORDER BY clause or NULL */
ExprList *pResultSet; /* Result set of the query */ ExprList *pResultSet; /* Result set of the query */
Expr *pWhere; /* The complete WHERE clause */ Expr *pWhere; /* The complete WHERE clause */
#ifndef SQLITE_OMIT_VIRTUALTABLE
Select *pLimit; /* Used to access LIMIT expr/registers for vtabs */
#endif
int aiCurOnePass[2]; /* OP_OpenWrite cursors for the ONEPASS opt */ int aiCurOnePass[2]; /* OP_OpenWrite cursors for the ONEPASS opt */
int iContinue; /* Jump here to continue with next record */ int iContinue; /* Jump here to continue with next record */
int iBreak; /* Jump here to break out of the loop */ int iBreak; /* Jump here to break out of the loop */
@@ -538,6 +541,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
void sqlite3WhereClauseInit(WhereClause*,WhereInfo*); void sqlite3WhereClauseInit(WhereClause*,WhereInfo*);
void sqlite3WhereClauseClear(WhereClause*); void sqlite3WhereClauseClear(WhereClause*);
void sqlite3WhereSplit(WhereClause*,Expr*,u8); void sqlite3WhereSplit(WhereClause*,Expr*,u8);
void sqlite3WhereAddLimit(WhereClause*, Select*);
Bitmask sqlite3WhereExprUsage(WhereMaskSet*, Expr*); Bitmask sqlite3WhereExprUsage(WhereMaskSet*, Expr*);
Bitmask sqlite3WhereExprUsageNN(WhereMaskSet*, Expr*); Bitmask sqlite3WhereExprUsageNN(WhereMaskSet*, Expr*);
Bitmask sqlite3WhereExprListUsage(WhereMaskSet*, ExprList*); Bitmask sqlite3WhereExprListUsage(WhereMaskSet*, ExprList*);

View File

@@ -2358,7 +2358,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
/* Loop through table entries that match term pOrTerm. */ /* Loop through table entries that match term pOrTerm. */
ExplainQueryPlan((pParse, 1, "INDEX %d", ii+1)); ExplainQueryPlan((pParse, 1, "INDEX %d", ii+1));
WHERETRACE(0xffff, ("Subplan for OR-clause:\n")); WHERETRACE(0xffff, ("Subplan for OR-clause:\n"));
pSubWInfo = sqlite3WhereBegin(pParse, pOrTab, pOrExpr, 0, 0, pSubWInfo = sqlite3WhereBegin(pParse, pOrTab, pOrExpr, 0, 0, 0,
WHERE_OR_SUBCLAUSE, iCovCur); WHERE_OR_SUBCLAUSE, iCovCur);
assert( pSubWInfo || pParse->nErr ); assert( pSubWInfo || pParse->nErr );
if( pSubWInfo ){ if( pSubWInfo ){

View File

@@ -1522,6 +1522,80 @@ void sqlite3WhereSplit(WhereClause *pWC, Expr *pExpr, u8 op){
} }
} }
/*
** Add either a LIMIT (if eMatchOp==SQLITE_INDEX_CONSTRAINT_LIMIT) or
** OFFSET (if eMatchOp==SQLITE_INDEX_CONSTRAINT_OFFSET) term to the
** where-clause passed as the first argument. The value for the term
** is found in register iReg.
*/
void whereAddLimitExpr(WhereClause *pWC, int iReg, int iCsr, int eMatchOp){
Parse *pParse = pWC->pWInfo->pParse;
sqlite3 *db = pParse->db;
Expr *pExpr;
pExpr = sqlite3PExpr(pParse, TK_MATCH, 0, sqlite3Expr(db,TK_REGISTER,0));
if( pExpr ){
WhereTerm *pTerm;
int idx;
pExpr->pRight->iTable = iReg;
idx = whereClauseInsert(pWC, pExpr, TERM_DYNAMIC|TERM_VIRTUAL);
pTerm = &pWC->a[idx];
pTerm->leftCursor = iCsr;
pTerm->eOperator = WO_AUX;
pTerm->eMatchOp = eMatchOp;
}
}
/*
** Possibly add terms corresponding to the LIMIT and OFFSET clauses of the
** SELECT statement passed as the second argument. These terms are only
** added if:
**
** 1. The SELECT statement has a LIMIT clause, and
** 2. The SELECT statement is not an aggregate or DISTINCT query, and
** 3. The SELECT statement has exactly one object in its from clause, and
** that object is a virtual table, and
** 4. There are no terms in the WHERE clause that will not be passed
** to the virtual table xBestIndex method.
** 5. The ORDER BY clause, if any, will be made available to the xBestIndex
** method.
**
** LIMIT and OFFSET terms are ignored by most of the planner code. They
** exist only so that they may be passed to the xBestIndex method of the
** single virtual table in the FROM clause of the SELECT.
*/
void sqlite3WhereAddLimit(WhereClause *pWC, Select *p){
assert( p==0 || (p->pGroupBy==0 && (p->selFlags & SF_Aggregate)==0) );
if( (p && p->pLimit) /* 1 */
&& (p->selFlags & (SF_Distinct|SF_Aggregate))==0 /* 2 */
&& (p->pSrc->nSrc==1 && IsVirtual(p->pSrc->a[0].pTab)) /* 3 */
){
ExprList *pOrderBy = p->pOrderBy;
int iCsr = p->pSrc->a[0].iCursor;
int ii;
/* Check condition (4). Return early if it is not met. */
for(ii=0; ii<pWC->nTerm; ii++){
if( pWC->a[ii].leftCursor!=iCsr ) return;
}
/* Check condition (5). Return early if it is not met. */
if( pOrderBy ){
for(ii=0; ii<pOrderBy->nExpr; ii++){
Expr *pExpr = pOrderBy->a[ii].pExpr;
if( pExpr->op!=TK_COLUMN || pExpr->iTable!=iCsr ) return;
if( pOrderBy->a[ii].sortFlags & KEYINFO_ORDER_BIGNULL ) return;
}
}
/* All conditions are met. Add the terms to the where-clause object. */
whereAddLimitExpr(pWC, p->iLimit, iCsr, SQLITE_INDEX_CONSTRAINT_LIMIT);
if( p->iOffset>0 ){
whereAddLimitExpr(pWC, p->iOffset, iCsr, SQLITE_INDEX_CONSTRAINT_OFFSET);
}
}
}
/* /*
** Initialize a preallocated WhereClause structure. ** Initialize a preallocated WhereClause structure.
*/ */