From: drh <> Date: Mon, 8 Nov 2021 16:38:08 +0000 (+0000) Subject: Add assert()s that verify that cursor numbers on subqueries are always X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=refs%2Fheads%2Fwell-ordered-cursors;p=thirdparty%2Fsqlite.git Add assert()s that verify that cursor numbers on subqueries are always greater than outer cursor numbers. Except, this is not always true in the presence of query flattening. We might need to relax that constraint. This branch will probably become a dead-end. For now it is saved for reference. FossilOrigin-Name: 6f4369666efb8eed84c3d60118baaf35d733ea906df983aeca2b0a475a6298a3 --- diff --git a/manifest b/manifest index 6e1e5337d6..eef4e55075 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Ensure\sthat\sthe\swindow\sfunction\srewrite\sdoes\snot\sleave\sthe\sparse\stree\nin\san\sinvalid\sstate\sthat\smight\scause\sproblems\sdownstream\sbefore\sthe\nerror\sis\srecognized\sand\sunwinds\sthe\sstack.\s\sAlso\stake\ssteps\ssuch\sthat\nan\sinvalid\sparse\stree\sdoes\snot\scause\sproblems\seven\sif\sit\sgoes\s\nunrecognized.\s\s\n[forum:/forumpost/398e9d5aa9|Forum\spost\s398e9d5aa9]. -D 2021-11-07T23:33:01.004 +C Add\sassert()s\sthat\sverify\sthat\scursor\snumbers\son\ssubqueries\sare\salways\ngreater\sthan\souter\scursor\snumbers.\s\sExcept,\sthis\sis\snot\salways\strue\sin\sthe\npresence\sof\squery\sflattening.\s\sWe\smight\sneed\sto\srelax\sthat\sconstraint.\nThis\sbranch\swill\sprobably\sbecome\sa\sdead-end.\s\sFor\snow\sit\sis\ssaved\sfor\nreference. +D 2021-11-08T16:38:08.067 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -502,7 +502,7 @@ F src/date.c fa928630fecf1d436cdc7a7a5c950c781709023ca782c21b7a43cc7361a9451e F src/dbpage.c 8a01e865bf8bc6d7b1844b4314443a6436c07c3efe1d488ed89e81719047833a F src/dbstat.c 861e08690fcb0f2ee1165eff0060ea8d4f3e2ea10f80dab7d32ad70443a6ff2d F src/delete.c 0c151975fa99560767d7747f9b60543d0093d9f8b89f13d2d6058e9c83ad19e7 -F src/expr.c f96439c1c58fd8dbb42254ad45339b8487f7e2c0b59eb43b4652ffe458205bdb +F src/expr.c 2d06e9ee4faec27601bd536042fda2ec260c5b142cc3abfd2f6751eb8c605977 F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007 F src/fkey.c 187b67af20c5795953a592832c5d985e4313fe503ebd8f95e3e9e9ad5a730bb5 F src/func.c 1cfb09d7ffca81238eccefdb0293e1f5b7cfebbd1816dfad5ec6024742a7496b @@ -550,12 +550,12 @@ F src/printf.c 5901672228f305f7d493cbc4e7d76a61a5caecdbc1cd06b1f9ec42ea4265cf8d F src/random.c 097dc8b31b8fba5a9aca1697aeb9fd82078ec91be734c16bffda620ced7ab83c F src/resolve.c ae65c88f5d0d4bc0052b203773d407efa2387c2bd6b202f87178006c7bb8632c F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92 -F src/select.c b4b3a0f32e70d93efbb357783846853dbd8b266ec0d7035aa0a245c33eecf72d +F src/select.c ac16dee42af39682bfd67539e127698838a2542601ee2eb6ce49196ba7265c74 F src/shell.c.in f8854bcb0d14707d661732698d5210d7f01694000c46e8014b323ad18f575be6 F src/sqlite.h.in 5cd209ac7dc4180f0e19292846f40440b8488015849ca0110c70b906b57d68f0 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h 8ff2fd2c166150b2e48639f5e506fb44e29f1a3f65031710b9e89d1c126ac839 -F src/sqliteInt.h c280f33f023f87864fa660925f5d5cb49ccfc82eea223fec4e37177c86a26b5a +F src/sqliteInt.h ab88d3f3d86dae6b2029539938fe742884811c9e64307d71ed0b991657262b38 F src/sqliteLimit.h d7323ffea5208c6af2734574bae933ca8ed2ab728083caa117c9738581a31657 F src/status.c 4b8bc2a6905163a38b739854a35b826c737333fab5b1f8e03fa7eb9a4799c4c1 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1 @@ -1931,7 +1931,10 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 0dc963f63aebc42960125f96865029f16b3f6867126aab350da12882505edb82 -R 3e89981cb2c8fbf47d84ee585ebde83e +P 0f9fc6b6073365d5159cd71e7fe08f8dadbc7b42abd324361e809502f4359155 +R 4f74580fd63b4e2f86db712346f3cd4a +T *branch * well-ordered-cursors +T *sym-well-ordered-cursors * +T -sym-trunk * U drh -Z 073fd661537b1ec07fc06b4c7f20875c +Z ae9ad8ca1734f1ca1c3ca8135a32d6c4 diff --git a/manifest.uuid b/manifest.uuid index fe0c9ac0b1..e49a26ce14 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -0f9fc6b6073365d5159cd71e7fe08f8dadbc7b42abd324361e809502f4359155 \ No newline at end of file +6f4369666efb8eed84c3d60118baaf35d733ea906df983aeca2b0a475a6298a3 \ No newline at end of file diff --git a/src/expr.c b/src/expr.c index 61e84e56ba..25d6cdc758 100644 --- a/src/expr.c +++ b/src/expr.c @@ -5878,6 +5878,62 @@ int sqlite3ExprCoveredByIndex( return !w.eCode; } +#ifdef SQLITE_DEBUG +/* Walker callback for recursion in sqlite3WellOrderedCursors() +*/ +static int wellOrderedCursors(Walker *pWalker, Select *pSel){ + pWalker->eCode = + sqlite3WellOrderedCursors(pWalker->pParse, pSel, pWalker->u.iCur); + return WRC_Abort; +} + +/* +** Check every cursor number in pSelect. Return false (zero) if any cursor +** number is less than or equal to iLowerBound. Return true if all cursors +** number are greater than iLowerBound. +** +** Repeat this check recursively on subqueries. +** +** Use this routine inside of an assert() to verify that every subquery +** cursor number is greater than the cursor numbers in all outer queries. +** This cursor number invariant is required for scoping of aggregate +** functions. tag-20211108 +*/ +int sqlite3WellOrderedCursors(Parse *pParse, Select *pSelect, int iLowerBound){ + Walker w; + SrcList *pSrc; + int i; + int mx = 0; + + pSrc = pSelect->pSrc; + assert( pSrc!=0 ); + for(i=0; inSrc; i++){ + int iThis = pSrc->a[i].iCursor; + if( iThis<=iLowerBound ){ + SELECTTRACE(1,pParse,pSelect, + ("Cursor %d less than cursor %d in outer query\n",iThis, iLowerBound)); + return 0; + } + if( iThis>mx ){ + mx = iThis; + } + } + memset(&w, 0, sizeof(w)); + w.pParse = pParse; + w.xSelectCallback = wellOrderedCursors; + w.xExprCallback = sqlite3ExprWalkNoop; + w.eCode = 1; + w.u.iCur = mx; + while( w.eCode ){ + sqlite3WalkSelectExpr(&w, pSelect); + if( w.eCode==0 ) break; + sqlite3WalkSelectFrom(&w, pSelect); + pSelect = pSelect->pPrior; + if( pSelect==0 ) break; + } + return w.eCode; +} +#endif /* SQLITE_DEBUG */ /* ** An instance of the following structure is used by the tree walker @@ -5929,7 +5985,9 @@ static int exprSrcCount(Walker *pWalker, Expr *pExpr){ }else if( pExpr->iTableiSrcInner ){ /* In a well-formed parse tree (no name resolution errors), ** TK_COLUMN nodes with smaller Expr.iTable values are in an - ** outer context. Those are the only ones to count as "other" */ + ** outer context. Those are the only ones to count as "other" + ** See tag-20211108 + */ p->nOther++; } } diff --git a/src/select.c b/src/select.c index ebb746467d..8c9420fd67 100644 --- a/src/select.c +++ b/src/select.c @@ -6404,6 +6404,7 @@ int sqlite3Select( sqlite3TreeViewSelect(0, p, 0); } #endif + assert( sqlite3WellOrderedCursors(pParse, p, -1) ); #endif /* SQLITE_OMIT_WINDOWFUNC */ pTabList = p->pSrc; isAgg = (p->selFlags & SF_Aggregate)!=0; @@ -6522,6 +6523,7 @@ int sqlite3Select( if( pParse->nErr ) goto select_end; /* This subquery can be absorbed into its parent. */ i = -1; + assert( sqlite3WellOrderedCursors(pParse, p, -1) ); } pTabList = p->pSrc; if( db->mallocFailed ) goto select_end; diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 984b3c680c..b7f967c43f 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -4623,6 +4623,9 @@ void sqlite3AggInfoPersistWalkerInit(Walker*,Parse*); void sqlite3ExprAnalyzeAggregates(NameContext*, Expr*); void sqlite3ExprAnalyzeAggList(NameContext*,ExprList*); int sqlite3ExprCoveredByIndex(Expr*, int iCur, Index *pIdx); +#ifdef SQLITE_DEBUG +int sqlite3WellOrderedCursors(Parse*,Select*,int); +#endif int sqlite3FunctionUsesThisSrc(Expr*, SrcList*); Vdbe *sqlite3GetVdbe(Parse*); #ifndef SQLITE_UNTESTABLE