From 132f96fc75496d93cc01be7dabb11eea55bddea2 Mon Sep 17 00:00:00 2001 From: drh <> Date: Wed, 8 Dec 2021 16:07:22 +0000 Subject: [PATCH] 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 --- manifest | 20 ++++++++++---------- manifest.uuid | 2 +- src/where.c | 9 +++++---- src/whereInt.h | 1 + src/wherecode.c | 6 +++--- src/whereexpr.c | 10 ++++++++++ 6 files changed, 30 insertions(+), 18 deletions(-) diff --git a/manifest b/manifest index bd016deb39..d59214aeb8 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\san\sOOB\sread\sthat\scould\soccur\sin\sfts5\swhen\sprocessing\scorrupt\srecords. -D 2021-12-06T18:57:02.055 +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-08T16:07:22.778 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -638,10 +638,10 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9 F src/wal.c ed0398a7adf02c31e34aada42cc86c58f413a7afe5f741a5d373ad087abde028 F src/wal.h c3aa7825bfa2fe0d85bef2db94655f99870a285778baa36307c0a16da32b226a F src/walker.c f890a3298418d7cba3b69b8803594fdc484ea241206a8dfa99db6dd36f8cbb3b -F src/where.c 5bd26902ddf3e385c0df9429b10e7358bbd0430c470ec1d2a53065723c4a55d2 -F src/whereInt.h 1630d9418512b080598e9a72b8af6b8bd1b9ab13fee1458f151762b6df206791 -F src/wherecode.c 1f5b62f46d284c8886945eb7438415bc27e23e87bb60b9ee468fa6bd31268f33 -F src/whereexpr.c 19394cb463003e9cc9305730b1508b8817a22bb7247170d81234b691a7f05b89 +F src/where.c 6e07a2ebfccedec1926f9cd13f773741002a56c40dd90adc3ea25e41354db46f +F src/whereInt.h 14ebb040acac47091a4dd3075f4ab511cad7fc31010fc5e6a750e06b7950c021 +F src/wherecode.c 280f1f87311827f8921a815dbb9b8e84bb394556716fa6a2e111c855b299de20 +F src/whereexpr.c 791544603b254cf11f8e84e3b50b0863c57322e9f213b828680f658e232ebc57 F src/window.c 5d3b397b0c026d0ff5890244ac41359e524c01ae31e78782e1ff418c3e271a9e F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/affinity2.test ce1aafc86e110685b324e9a763eab4f2a73f737842ec3b687bd965867de90627 @@ -1934,7 +1934,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 8fd5b8ec4ab9b5554d27f25a4638d56e347eab78b60900f24b15a815d3731330 -R c3401645c738abc52212977ced7d66bd -U dan -Z bbca536d76f68538aaa5d06c505e1b60 +P bb9b1a15f7e80483162049dfd981d059dc69d03348b521f7ac164a8cd3ae3cc4 +R 2e19e97323a5794a031526354d3fd247 +U drh +Z 8c650a14815db39748cc380bbb1958b3 diff --git a/manifest.uuid b/manifest.uuid index 85e543009e..4c34bfe654 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -bb9b1a15f7e80483162049dfd981d059dc69d03348b521f7ac164a8cd3ae3cc4 \ No newline at end of file +6024682ca467fa4fe49608772b0bbfa2f8a419b32cebfa715941073c8b29da49 \ No newline at end of file diff --git a/src/where.c b/src/where.c index f1abd5483c..649b786520 100644 --- a/src/where.c +++ b/src/where.c @@ -2361,11 +2361,11 @@ static void whereLoopOutputAdjust( LogEst iReduce = 0; /* pLoop->nOut should not exceed nRow-iReduce */ 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 ); - if( (pTerm->wtFlags & TERM_VIRTUAL)!=0 ) break; - if( (pTerm->prereqAll & pLoop->maskSelf)==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--){ pX = pLoop->aLTerm[j]; if( pX==0 ) continue; @@ -3636,6 +3636,7 @@ static int whereLoopAddOr( tempWC.pOuter = pWC; tempWC.op = TK_AND; tempWC.nTerm = 1; + tempWC.nBase = 1; tempWC.a = pOrTerm; sSubBuild.pWC = &tempWC; }else{ @@ -5085,7 +5086,7 @@ WhereInfo *sqlite3WhereBegin( ** FROM ... WHERE random()>0; -- eval random() once per row ** FROM ... WHERE (SELECT random())>0; -- eval random() once overall */ - for(ii=0; iinTerm; ii++){ + for(ii=0; iinBase; ii++){ WhereTerm *pT = &sWLB.pWC->a[ii]; if( pT->wtFlags & TERM_VIRTUAL ) continue; if( pT->prereqAll==0 && (nTabList==0 || exprIsDeterministic(pT->pExpr)) ){ diff --git a/src/whereInt.h b/src/whereInt.h index 217dd0ba2a..0df84ad6c0 100644 --- a/src/whereInt.h +++ b/src/whereInt.h @@ -320,6 +320,7 @@ struct WhereClause { u8 hasOr; /* True if any a[].eOperator is WO_OR */ int nTerm; /* Number of terms */ 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 */ #if defined(SQLITE_SMALL_STACK) WhereTerm aStatic[1]; /* Initial static space for a[] */ diff --git a/src/wherecode.c b/src/wherecode.c index 460ac4fe30..a6633967a2 100644 --- a/src/wherecode.c +++ b/src/wherecode.c @@ -970,7 +970,7 @@ static void codeCursorHint( sWalker.pParse = pParse; sWalker.u.pCCurHint = &sHint; pWC = &pWInfo->sWC; - for(i=0; inTerm; i++){ + for(i=0; inBase; i++){ pTerm = &pWC->a[i]; if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) 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 ** 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; WhereTerm *pAlt; if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue; @@ -2512,7 +2512,7 @@ Bitmask sqlite3WhereCodeOneLoopStart( pLevel->addrFirst = sqlite3VdbeCurrentAddr(v); sqlite3VdbeAddOp2(v, OP_Integer, 1, pLevel->iLeftJoin); VdbeComment((v, "record LEFT JOIN hit")); - for(pTerm=pWC->a, j=0; jnTerm; j++, pTerm++){ + for(pTerm=pWC->a, j=0; jnBase; j++, pTerm++){ testcase( pTerm->wtFlags & TERM_VIRTUAL ); testcase( pTerm->wtFlags & TERM_CODED ); if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue; diff --git a/src/whereexpr.c b/src/whereexpr.c index eff7f4ab22..5a3fbe2d7f 100644 --- a/src/whereexpr.c +++ b/src/whereexpr.c @@ -79,6 +79,7 @@ static int whereClauseInsert(WhereClause *pWC, Expr *p, u16 wtFlags){ pWC->nSlot = sqlite3DbMallocSize(db, pWC->a)/sizeof(pWC->a[0]); } pTerm = &pWC->a[idx = pWC->nTerm++]; + if( (wtFlags & TERM_VIRTUAL)==0 ) pWC->nBase = pWC->nTerm; if( p && ExprHasProperty(p, EP_Unlikely) ){ pTerm->truthProb = sqlite3LogEst(p->iTable) - 270; }else{ @@ -1532,6 +1533,7 @@ void sqlite3WhereClauseInit( pWC->hasOr = 0; pWC->pOuter = 0; pWC->nTerm = 0; + pWC->nBase = 0; pWC->nSlot = ArraySize(pWC->aStatic); pWC->a = pWC->aStatic; } @@ -1543,9 +1545,17 @@ void sqlite3WhereClauseInit( */ void sqlite3WhereClauseClear(WhereClause *pWC){ sqlite3 *db = pWC->pWInfo->pParse->db; + assert( pWC->nTerm>=pWC->nBase ); if( pWC->nTerm>0 ){ WhereTerm *a = pWC->a; 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; inTerm; i++){ + assert( (pWC->a[i].wtFlags & TERM_VIRTUAL)!=0 ); + } +#endif while(1){ if( a->wtFlags & TERM_DYNAMIC ){ sqlite3ExprDelete(db, a->pExpr);