1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-11-18 10:21:03 +03:00

In the WhereClause object, do not assume that all TERM_VIRTUAL terms appear

at the end of the list, because that is no longer true.  Instead, keep a
separate nBase count that is the size of the list excluding the tail of
virtual terms.  Use nBase instead of nTerm when scanning terms that are not
virtual.  Add assert()s to validate correctness of WhereClause.

FossilOrigin-Name: 6024682ca467fa4fe49608772b0bbfa2f8a419b32cebfa715941073c8b29da49
This commit is contained in:
drh
2021-12-08 16:07:22 +00:00
parent c436b3056d
commit 132f96fc75
6 changed files with 30 additions and 18 deletions

View File

@@ -1,5 +1,5 @@
C Fix\san\sOOB\sread\sthat\scould\soccur\sin\sfts5\swhen\sprocessing\scorrupt\srecords. C In\sthe\sWhereClause\sobject,\sdo\snot\sassume\sthat\sall\sTERM_VIRTUAL\sterms\sappear\nat\sthe\send\sof\sthe\slist,\sbecause\sthat\sis\sno\slonger\strue.\s\sInstead,\skeep\sa\nseparate\snBase\scount\sthat\sis\sthe\ssize\sof\sthe\slist\sexcluding\sthe\stail\sof\nvirtual\sterms.\s\sUse\snBase\sinstead\sof\snTerm\swhen\sscanning\sterms\sthat\sare\snot\nvirtual.\s\sAdd\sassert()s\sto\svalidate\scorrectness\sof\sWhereClause.
D 2021-12-06T18:57:02.055 D 2021-12-08T16:07:22.778
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
@@ -638,10 +638,10 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
F src/wal.c ed0398a7adf02c31e34aada42cc86c58f413a7afe5f741a5d373ad087abde028 F src/wal.c ed0398a7adf02c31e34aada42cc86c58f413a7afe5f741a5d373ad087abde028
F src/wal.h c3aa7825bfa2fe0d85bef2db94655f99870a285778baa36307c0a16da32b226a F src/wal.h c3aa7825bfa2fe0d85bef2db94655f99870a285778baa36307c0a16da32b226a
F src/walker.c f890a3298418d7cba3b69b8803594fdc484ea241206a8dfa99db6dd36f8cbb3b F src/walker.c f890a3298418d7cba3b69b8803594fdc484ea241206a8dfa99db6dd36f8cbb3b
F src/where.c 5bd26902ddf3e385c0df9429b10e7358bbd0430c470ec1d2a53065723c4a55d2 F src/where.c 6e07a2ebfccedec1926f9cd13f773741002a56c40dd90adc3ea25e41354db46f
F src/whereInt.h 1630d9418512b080598e9a72b8af6b8bd1b9ab13fee1458f151762b6df206791 F src/whereInt.h 14ebb040acac47091a4dd3075f4ab511cad7fc31010fc5e6a750e06b7950c021
F src/wherecode.c 1f5b62f46d284c8886945eb7438415bc27e23e87bb60b9ee468fa6bd31268f33 F src/wherecode.c 280f1f87311827f8921a815dbb9b8e84bb394556716fa6a2e111c855b299de20
F src/whereexpr.c 19394cb463003e9cc9305730b1508b8817a22bb7247170d81234b691a7f05b89 F src/whereexpr.c 791544603b254cf11f8e84e3b50b0863c57322e9f213b828680f658e232ebc57
F src/window.c 5d3b397b0c026d0ff5890244ac41359e524c01ae31e78782e1ff418c3e271a9e F src/window.c 5d3b397b0c026d0ff5890244ac41359e524c01ae31e78782e1ff418c3e271a9e
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
F test/affinity2.test ce1aafc86e110685b324e9a763eab4f2a73f737842ec3b687bd965867de90627 F test/affinity2.test ce1aafc86e110685b324e9a763eab4f2a73f737842ec3b687bd965867de90627
@@ -1934,7 +1934,7 @@ 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 8fd5b8ec4ab9b5554d27f25a4638d56e347eab78b60900f24b15a815d3731330 P bb9b1a15f7e80483162049dfd981d059dc69d03348b521f7ac164a8cd3ae3cc4
R c3401645c738abc52212977ced7d66bd R 2e19e97323a5794a031526354d3fd247
U dan U drh
Z bbca536d76f68538aaa5d06c505e1b60 Z 8c650a14815db39748cc380bbb1958b3

View File

@@ -1 +1 @@
bb9b1a15f7e80483162049dfd981d059dc69d03348b521f7ac164a8cd3ae3cc4 6024682ca467fa4fe49608772b0bbfa2f8a419b32cebfa715941073c8b29da49

View File

@@ -2361,11 +2361,11 @@ static void whereLoopOutputAdjust(
LogEst iReduce = 0; /* pLoop->nOut should not exceed nRow-iReduce */ LogEst iReduce = 0; /* pLoop->nOut should not exceed nRow-iReduce */
assert( (pLoop->wsFlags & WHERE_AUTO_INDEX)==0 ); assert( (pLoop->wsFlags & WHERE_AUTO_INDEX)==0 );
for(i=pWC->nTerm, pTerm=pWC->a; i>0; i--, pTerm++){ for(i=pWC->nBase, pTerm=pWC->a; i>0; i--, pTerm++){
assert( pTerm!=0 ); assert( pTerm!=0 );
if( (pTerm->wtFlags & TERM_VIRTUAL)!=0 ) break;
if( (pTerm->prereqAll & pLoop->maskSelf)==0 ) continue;
if( (pTerm->prereqAll & notAllowed)!=0 ) continue; if( (pTerm->prereqAll & notAllowed)!=0 ) continue;
if( (pTerm->prereqAll & pLoop->maskSelf)==0 ) continue;
if( (pTerm->wtFlags & TERM_VIRTUAL)!=0 ) continue;
for(j=pLoop->nLTerm-1; j>=0; j--){ for(j=pLoop->nLTerm-1; j>=0; j--){
pX = pLoop->aLTerm[j]; pX = pLoop->aLTerm[j];
if( pX==0 ) continue; if( pX==0 ) continue;
@@ -3636,6 +3636,7 @@ static int whereLoopAddOr(
tempWC.pOuter = pWC; tempWC.pOuter = pWC;
tempWC.op = TK_AND; tempWC.op = TK_AND;
tempWC.nTerm = 1; tempWC.nTerm = 1;
tempWC.nBase = 1;
tempWC.a = pOrTerm; tempWC.a = pOrTerm;
sSubBuild.pWC = &tempWC; sSubBuild.pWC = &tempWC;
}else{ }else{
@@ -5085,7 +5086,7 @@ WhereInfo *sqlite3WhereBegin(
** FROM ... WHERE random()>0; -- eval random() once per row ** FROM ... WHERE random()>0; -- eval random() once per row
** FROM ... WHERE (SELECT random())>0; -- eval random() once overall ** FROM ... WHERE (SELECT random())>0; -- eval random() once overall
*/ */
for(ii=0; ii<sWLB.pWC->nTerm; ii++){ for(ii=0; ii<sWLB.pWC->nBase; ii++){
WhereTerm *pT = &sWLB.pWC->a[ii]; WhereTerm *pT = &sWLB.pWC->a[ii];
if( pT->wtFlags & TERM_VIRTUAL ) continue; if( pT->wtFlags & TERM_VIRTUAL ) continue;
if( pT->prereqAll==0 && (nTabList==0 || exprIsDeterministic(pT->pExpr)) ){ if( pT->prereqAll==0 && (nTabList==0 || exprIsDeterministic(pT->pExpr)) ){

View File

@@ -320,6 +320,7 @@ struct WhereClause {
u8 hasOr; /* True if any a[].eOperator is WO_OR */ u8 hasOr; /* True if any a[].eOperator is WO_OR */
int nTerm; /* Number of terms */ int nTerm; /* Number of terms */
int nSlot; /* Number of entries in a[] */ int nSlot; /* Number of entries in a[] */
int nBase; /* Number of terms through the last non-Virtual */
WhereTerm *a; /* Each a[] describes a term of the WHERE cluase */ WhereTerm *a; /* Each a[] describes a term of the WHERE cluase */
#if defined(SQLITE_SMALL_STACK) #if defined(SQLITE_SMALL_STACK)
WhereTerm aStatic[1]; /* Initial static space for a[] */ WhereTerm aStatic[1]; /* Initial static space for a[] */

View File

@@ -970,7 +970,7 @@ static void codeCursorHint(
sWalker.pParse = pParse; sWalker.pParse = pParse;
sWalker.u.pCCurHint = &sHint; sWalker.u.pCCurHint = &sHint;
pWC = &pWInfo->sWC; pWC = &pWInfo->sWC;
for(i=0; i<pWC->nTerm; i++){ for(i=0; i<pWC->nBase; i++){
pTerm = &pWC->a[i]; pTerm = &pWC->a[i];
if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue; if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
if( pTerm->prereqAll & pLevel->notReady ) continue; if( pTerm->prereqAll & pLevel->notReady ) continue;
@@ -2467,7 +2467,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
** then we cannot use the "t1.a=t2.b" constraint, but we can code ** then we cannot use the "t1.a=t2.b" constraint, but we can code
** the implied "t1.a=123" constraint. ** the implied "t1.a=123" constraint.
*/ */
for(pTerm=pWC->a, j=pWC->nTerm; j>0; j--, pTerm++){ for(pTerm=pWC->a, j=pWC->nBase; j>0; j--, pTerm++){
Expr *pE, sEAlt; Expr *pE, sEAlt;
WhereTerm *pAlt; WhereTerm *pAlt;
if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue; if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
@@ -2512,7 +2512,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
pLevel->addrFirst = sqlite3VdbeCurrentAddr(v); pLevel->addrFirst = sqlite3VdbeCurrentAddr(v);
sqlite3VdbeAddOp2(v, OP_Integer, 1, pLevel->iLeftJoin); sqlite3VdbeAddOp2(v, OP_Integer, 1, pLevel->iLeftJoin);
VdbeComment((v, "record LEFT JOIN hit")); VdbeComment((v, "record LEFT JOIN hit"));
for(pTerm=pWC->a, j=0; j<pWC->nTerm; j++, pTerm++){ for(pTerm=pWC->a, j=0; j<pWC->nBase; j++, pTerm++){
testcase( pTerm->wtFlags & TERM_VIRTUAL ); testcase( pTerm->wtFlags & TERM_VIRTUAL );
testcase( pTerm->wtFlags & TERM_CODED ); testcase( pTerm->wtFlags & TERM_CODED );
if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue; if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;

View File

@@ -79,6 +79,7 @@ static int whereClauseInsert(WhereClause *pWC, Expr *p, u16 wtFlags){
pWC->nSlot = sqlite3DbMallocSize(db, pWC->a)/sizeof(pWC->a[0]); pWC->nSlot = sqlite3DbMallocSize(db, pWC->a)/sizeof(pWC->a[0]);
} }
pTerm = &pWC->a[idx = pWC->nTerm++]; pTerm = &pWC->a[idx = pWC->nTerm++];
if( (wtFlags & TERM_VIRTUAL)==0 ) pWC->nBase = pWC->nTerm;
if( p && ExprHasProperty(p, EP_Unlikely) ){ if( p && ExprHasProperty(p, EP_Unlikely) ){
pTerm->truthProb = sqlite3LogEst(p->iTable) - 270; pTerm->truthProb = sqlite3LogEst(p->iTable) - 270;
}else{ }else{
@@ -1532,6 +1533,7 @@ void sqlite3WhereClauseInit(
pWC->hasOr = 0; pWC->hasOr = 0;
pWC->pOuter = 0; pWC->pOuter = 0;
pWC->nTerm = 0; pWC->nTerm = 0;
pWC->nBase = 0;
pWC->nSlot = ArraySize(pWC->aStatic); pWC->nSlot = ArraySize(pWC->aStatic);
pWC->a = pWC->aStatic; pWC->a = pWC->aStatic;
} }
@@ -1543,9 +1545,17 @@ void sqlite3WhereClauseInit(
*/ */
void sqlite3WhereClauseClear(WhereClause *pWC){ void sqlite3WhereClauseClear(WhereClause *pWC){
sqlite3 *db = pWC->pWInfo->pParse->db; sqlite3 *db = pWC->pWInfo->pParse->db;
assert( pWC->nTerm>=pWC->nBase );
if( pWC->nTerm>0 ){ if( pWC->nTerm>0 ){
WhereTerm *a = pWC->a; WhereTerm *a = pWC->a;
WhereTerm *aLast = &pWC->a[pWC->nTerm-1]; WhereTerm *aLast = &pWC->a[pWC->nTerm-1];
#ifdef SQLITE_DEBUG
int i;
/* Verify that every term past pWC->nBase is virtual */
for(i=pWC->nBase; i<pWC->nTerm; i++){
assert( (pWC->a[i].wtFlags & TERM_VIRTUAL)!=0 );
}
#endif
while(1){ while(1){
if( a->wtFlags & TERM_DYNAMIC ){ if( a->wtFlags & TERM_DYNAMIC ){
sqlite3ExprDelete(db, a->pExpr); sqlite3ExprDelete(db, a->pExpr);