From a9ebfe20309d5aeec90337099a27e68454d16ff6 Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 25 Dec 2019 23:54:21 +0000 Subject: [PATCH] When the sqlite3WindowRewrite() routine detects and error, have it convert the SELECT statement into just "SELECT null" so that it does not leave the parse tree in a goofy state that can cause problems with subsequent code before the stack has a chance to unwind and report the error. Ticket [d87336c81c7d0873] FossilOrigin-Name: fa58aad48a788802b13a819e49f9b8787f713bbe395c46c7295e821c52c81738 --- manifest | 20 ++++++++++---------- manifest.uuid | 2 +- src/expr.c | 7 +++++-- src/select.c | 27 +++++++++++++++++++++++---- src/sqliteInt.h | 3 ++- src/window.c | 12 +++++++++--- test/window1.test | 11 ++++++++++- 7 files changed, 60 insertions(+), 22 deletions(-) diff --git a/manifest b/manifest index 405691aeec..c938290f74 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\sminor\sperformance\sregression\sfrom\scheck-in\s[401c9d30e06191d9] -D 2019-12-24T21:42:22.593 +C When\sthe\ssqlite3WindowRewrite()\sroutine\sdetects\sand\serror,\shave\sit\sconvert\nthe\sSELECT\sstatement\sinto\sjust\s"SELECT\snull"\sso\sthat\sit\sdoes\snot\sleave\sthe\nparse\stree\sin\sa\sgoofy\sstate\sthat\scan\scause\sproblems\swith\ssubsequent\scode\nbefore\sthe\sstack\shas\sa\schance\sto\sunwind\sand\sreport\sthe\serror.\nTicket\s[d87336c81c7d0873] +D 2019-12-25T23:54:21.640 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -479,7 +479,7 @@ F src/date.c e1d8ac7102f3f283e63e13867acb0efa33861cf34f0faf4cdbaf9fa7a1eb7041 F src/dbpage.c 135eb3b5e74f9ef74bde5cec2571192c90c86984fa534c88bf4a055076fa19b7 F src/dbstat.c 6c407e549406c10fde9ac3987f6d734459205239ad370369bc5fcd683084a4fa F src/delete.c a5c59b9c0251cf7682bc52af0d64f09b1aefc6781a63592c8f1136f7b73c66e4 -F src/expr.c 518e46716bcf072b41e3e88209965e2495f4c7888f2f698ff00b3e415738912d +F src/expr.c 3a27de3630d2dec266423505f1ad38484096df4b6d80cf5c90076340d6b2b810 F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007 F src/fkey.c 92a248ec0fa4ed8ab60c98d9b188ce173aaf218f32e7737ba77deb2a684f9847 F src/func.c ed33e38cd642058182a31a3f518f2e34f4bbe53aa483335705c153c4d3e50b12 @@ -527,12 +527,12 @@ F src/printf.c 9be6945837c839ba57837b4bc3af349eba630920fa5532aa518816defe42a7d4 F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384 F src/resolve.c 86a7773d2892227ba9ad1721c41bb03c501830f1bf6de5f78dd0062b82e10c9d F src/rowset.c d977b011993aaea002cab3e0bb2ce50cf346000dff94e944d547b989f4b1fe93 -F src/select.c b895d809b93596c828c4cd79f4da96d48bf1969414877bb4313770000ea736cc +F src/select.c 338c1e7e2d88f1ecc47b3f0b1af73522baffe5b6461d86510bec80b70d9eb63f F src/shell.c.in 4a3a9e1c11847b1904f2b01d087af1c052f660902755abab457cab1756817ded F src/sqlite.h.in 2a23e8161775253d9cf383c2c6aa559005dc787d350dcb0be67a6c4cc3bd1d19 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h 72af51aa4e912e14cd495fb6e7fac65f0940db80ed950d90911aff292cc47ce2 -F src/sqliteInt.h eada1e78b6b950670eb4cc093ce6eb96a7df8bc548cabd7bc6127fa4fbce8ba5 +F src/sqliteInt.h 3e235c7a406630bff9fe7183d9af5d4ce21a9b7acb77bf1b82a0caa130a5f687 F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b F src/status.c 46e7aec11f79dad50965a5ca5fa9de009f7d6bde08be2156f1538a0a296d4d0e F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34 @@ -617,7 +617,7 @@ F src/where.c 58653781a4b31fa16b95b953591fdc1f1ed5ff77574e59b90a27da3819b60a46 F src/whereInt.h 4a296fd4fa79fdcbc2b5e8c1b898901617655811223e1082b899c23ecb092217 F src/wherecode.c bb58d5e6e7f583db5b74e0fd35f1d65fdee67d20553b55cd6098fc3f8148053a F src/whereexpr.c 4b34be1434183e7bb8a05d4bf42bd53ea53021b0b060936fbd12062b4ff6b396 -F src/window.c da010455914c81037dcb5b0c6f4273f8a32c94567865c46a60060b937b018a96 +F src/window.c a5b69ea3cd22555d390582771173a68c1b798a0847aef3bd9eb51792bc6fcacb F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/affinity2.test ce1aafc86e110685b324e9a763eab4f2a73f737842ec3b687bd965867de90627 F test/affinity3.test 6a101af2fc945ce2912f6fe54dd646018551710d @@ -1713,7 +1713,7 @@ F test/win32heap.test 10fd891266bd00af68671e702317726375e5407561d859be1aa04696f2 F test/win32lock.test fbf107c91d8f5512be5a5b87c4c42ab9fdd54972 F test/win32longpath.test 169c75a3b2e43481f4a62122510210c67b08f26d F test/win32nolock.test ac4f08811a562e45a5755e661f45ca85892bdbbc -F test/window1.test 790c9f12bc4c6f789216fb2c38bd1fbf5e191bed8b9a3712326e4af1a50222c0 +F test/window1.test 7968f1baa13e4f4399a65a21ae9c324a073c28c684adcda2ddf1ea25741d1faa F test/window2.tcl 114b217d4ffff891142023cc5f3131b0dae3ad149ac4b45a6ed9e2ad943f8ce2 F test/window2.test dea2ffecb7182a385143ea0eb368b6241ee43c5f971f4ad1c4337029cb1fc10a F test/window3.tcl acea6e86a4324a210fd608d06741010ca83ded9fde438341cb978c49928faf03 @@ -1852,7 +1852,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 ddb10f0374e66886d0681937b14cf0b4f100f03d3955b45b6c508dc6d9e36976 -R 5b1079c8a384ce37450b3fecba55c04d +P 76f54ee86777cbf530654323c953388ef64d0608516722d2522be6c859fa1382 +R c46405001dbbf37c4a4da195980c58c5 U drh -Z b050346f80259aa216b8caa58ba47eb4 +Z 7b421b0b8aa6e2e1e8fb7d8227a85505 diff --git a/manifest.uuid b/manifest.uuid index 7fc9e7916d..0ca15f04c1 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -76f54ee86777cbf530654323c953388ef64d0608516722d2522be6c859fa1382 \ No newline at end of file +fa58aad48a788802b13a819e49f9b8787f713bbe395c46c7295e821c52c81738 \ No newline at end of file diff --git a/src/expr.c b/src/expr.c index 601574e68e..7901608d2d 100644 --- a/src/expr.c +++ b/src/expr.c @@ -594,6 +594,7 @@ static void codeVectorCompare( int addrDone = sqlite3VdbeMakeLabel(pParse); int isCommuted = ExprHasProperty(pExpr,EP_Commuted); + if( pParse->nErr ) return; if( nLeft!=sqlite3ExprVectorSize(pRight) ){ sqlite3ErrorMsg(pParse, "row value misused"); return; @@ -2686,8 +2687,10 @@ static char *exprINAffinity(Parse *pParse, Expr *pExpr){ ** "sub-select returns N columns - expected M" */ void sqlite3SubselectError(Parse *pParse, int nActual, int nExpect){ - const char *zFmt = "sub-select returns %d columns - expected %d"; - sqlite3ErrorMsg(pParse, zFmt, nActual, nExpect); + if( pParse->nErr==0 ){ + const char *zFmt = "sub-select returns %d columns - expected %d"; + sqlite3ErrorMsg(pParse, zFmt, nActual, nExpect); + } } #endif diff --git a/src/select.c b/src/select.c index 6fff2883ec..60744e825a 100644 --- a/src/select.c +++ b/src/select.c @@ -84,7 +84,10 @@ struct SortCtx { /* ** Delete all the content of a Select structure. Deallocate the structure -** itself only if bFree is true. +** itself depending on the value of bFree +** +** If bFree==1, call sqlite3DbFree() on the p object. +** If bFree==0, Leave the first Select object unfreed */ static void clearSelect(sqlite3 *db, Select *p, int bFree){ while( p ){ @@ -188,6 +191,20 @@ void sqlite3SelectDelete(sqlite3 *db, Select *p){ if( OK_IF_ALWAYS_TRUE(p) ) clearSelect(db, p, 1); } +/* +** Delete all the substructure for p, but keep p allocated. Redefine +** p to be a single SELECT where every column of the result set has a +** value of NULL. +*/ +void sqlite3SelectReset(Parse *pParse, Select *p){ + if( ALWAYS(p) ){ + clearSelect(pParse->db, p, 0); + memset(&p->iLimit, 0, sizeof(Select) - offsetof(Select,iLimit)); + p->pEList = sqlite3ExprListAppend(pParse, 0, + sqlite3ExprAlloc(pParse->db,TK_NULL,0,0)); + } +} + /* ** Return a pointer to the right-most SELECT statement in a compound. */ @@ -2711,9 +2728,9 @@ static int multiSelect( ** it is that we currently need. */ assert( unionTab==dest.iSDParm || dest.eDest!=priorOp ); - if( dest.eDest!=priorOp ){ + assert( p->pEList || db->mallocFailed ); + if( dest.eDest!=priorOp && db->mallocFailed==0 ){ int iCont, iBreak, iStart; - assert( p->pEList ); iBreak = sqlite3VdbeMakeLabel(pParse); iCont = sqlite3VdbeMakeLabel(pParse); computeLimitRegisters(pParse, p, iBreak); @@ -5738,7 +5755,9 @@ int sqlite3Select( } #ifndef SQLITE_OMIT_WINDOWFUNC - if( sqlite3WindowRewrite(pParse, p) ){ + rc = sqlite3WindowRewrite(pParse, p); + if( rc ){ + assert( pParse->nErr>0 ); goto select_end; } #if SELECTTRACE_ENABLED diff --git a/src/sqliteInt.h b/src/sqliteInt.h index a8cdb9f6ad..c1ed684ffc 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -2918,13 +2918,13 @@ struct Upsert { ** sequences for the ORDER BY clause. */ struct Select { - ExprList *pEList; /* The fields of the result */ u8 op; /* One of: TK_UNION TK_ALL TK_INTERSECT TK_EXCEPT */ LogEst nSelectRow; /* Estimated number of result rows */ u32 selFlags; /* Various SF_* values */ int iLimit, iOffset; /* Memory registers holding LIMIT & OFFSET counters */ u32 selId; /* Unique identifier number for this SELECT */ int addrOpenEphm[2]; /* OP_OpenEphem opcodes related to this select */ + ExprList *pEList; /* The fields of the result */ SrcList *pSrc; /* The FROM clause */ Expr *pWhere; /* The WHERE clause */ ExprList *pGroupBy; /* The GROUP BY clause */ @@ -4092,6 +4092,7 @@ int sqlite3Select(Parse*, Select*, SelectDest*); Select *sqlite3SelectNew(Parse*,ExprList*,SrcList*,Expr*,ExprList*, Expr*,ExprList*,u32,Expr*); void sqlite3SelectDelete(sqlite3*, Select*); +void sqlite3SelectReset(Parse*, Select*); Table *sqlite3SrcListLookup(Parse*, SrcList*); int sqlite3IsReadOnly(Parse*, Table*, int); void sqlite3OpenTable(Parse*, int iCur, int iDb, Table*, int); diff --git a/src/window.c b/src/window.c index f4e12f5fdb..ab8f2c867a 100644 --- a/src/window.c +++ b/src/window.c @@ -1021,6 +1021,9 @@ int sqlite3WindowRewrite(Parse *pParse, Select *p){ pSub->selFlags |= SF_Expanded; pTab2 = sqlite3ResultSetOfSelect(pParse, pSub, SQLITE_AFF_NONE); if( pTab2==0 ){ + /* Might actually be some other kind of error, but in that case + ** pParse->nErr will be set, so if SQLITE_NOMEM is set, we will get + ** the correct error message regardless. */ rc = SQLITE_NOMEM; }else{ memcpy(pTab, pTab2, sizeof(Table)); @@ -1039,9 +1042,12 @@ int sqlite3WindowRewrite(Parse *pParse, Select *p){ sqlite3DbFree(db, pTab); } - if( rc && pParse->nErr==0 ){ - assert( pParse->db->mallocFailed ); - return sqlite3ErrorToParser(pParse->db, SQLITE_NOMEM); + if( rc ){ + if( pParse->nErr==0 ){ + assert( pParse->db->mallocFailed ); + sqlite3ErrorToParser(pParse->db, SQLITE_NOMEM); + } + sqlite3SelectReset(pParse, p); } return rc; } diff --git a/test/window1.test b/test/window1.test index fc729354bd..4249a58e83 100644 --- a/test/window1.test +++ b/test/window1.test @@ -1329,7 +1329,7 @@ do_execsql_test 37.20 { SELECT c FROM v0 WHERE c BETWEEN -10 AND 20; } {} -# 2019-20-20 mrigger reported problem with a FILTER clause on an aggregate +# 2019-12-20 mrigger reported problem with a FILTER clause on an aggregate # in a join. # reset_db @@ -1361,5 +1361,14 @@ do_execsql_test 39.4 { SELECT * FROM t0 WHERE (t0.c0, 1) IN(SELECT NTILE(1) OVER(), 0 FROM t0); } +# 2019-12-25 ticket d87336c81c7d0873 +# +reset_db +do_catchsql_test 40.1 { + CREATE VIRTUAL TABLE t0 USING rtree(c0, c1, c2); + SELECT * FROM t0 + WHERE ((0,0) IN (SELECT COUNT(*),LAG(5)OVER(PARTITION BY 0) FROM t0),0)<=(c1,0); +} {1 {1st ORDER BY term out of range - should be between 1 and 3}} + finish_test