From: drh <> Date: Mon, 11 Jan 2021 20:37:02 +0000 (+0000) Subject: Add a linked list of ParseCleanup objects to the end of a Parse object and X-Git-Tag: version-3.35.0~138^2~1 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=cf3c078f9326ac990fc4e1bfb4748e0b9f467069;p=thirdparty%2Fsqlite.git Add a linked list of ParseCleanup objects to the end of a Parse object and use that list as a place to put other sub-objects that need to be deallocated. Have a single such list for infrequently used sub-objects is more efficient than doing an a separate check for each kind of sub-object. FossilOrigin-Name: affa2b7b316941b8a6c4d0d1ff212c81a593faf1d05d129e14d2b70d73a25c59 --- diff --git a/manifest b/manifest index 5c6ea5e56e..fdfe62597e 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C New\sCLI\scommand:\s\s".stats\svmstep"\senables\sthe\sdisplay\sof\sthe\svirtual-machine\nstep\scount\sonly,\safter\seach\scommand.\s\sUseful\sfor\soptimization\sproblems. -D 2021-01-09T19:10:04.989 +C Add\sa\slinked\slist\sof\sParseCleanup\sobjects\sto\sthe\send\sof\sa\sParse\sobject\sand\nuse\sthat\slist\sas\sa\splace\sto\sput\sother\ssub-objects\sthat\sneed\sto\sbe\sdeallocated.\nHave\sa\ssingle\ssuch\slist\sfor\sinfrequently\sused\ssub-objects\sis\smore\sefficient\nthan\sdoing\san\sa\sseparate\scheck\sfor\seach\skind\sof\ssub-object. +D 2021-01-11T20:37:02.868 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -501,7 +501,7 @@ F src/hash.c 8d7dda241d0ebdafb6ffdeda3149a412d7df75102cecfc1021c98d6219823b19 F src/hash.h 9d56a9079d523b648774c1784b74b89bd93fac7b365210157482e4319a468f38 F src/hwtime.h cb1d7e3e1ed94b7aa6fde95ae2c2daccc3df826be26fc9ed7fd90d1750ae6144 F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71 -F src/insert.c 81b7ee72cd754b5d0018659d5593355f2d61b3d80f07f200167c4826846e907d +F src/insert.c 9ced988440d29531568bfe4f48c7b69035b100f6833ca1080abb710b7c415111 F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa F src/loadext.c 8c9c8cd2bd8eecdb06d9b6e89de7e9e65bae45cc8fc33609cc74023a5c296067 F src/main.c 97e9f137354bc1f76dc9bb60a0a24f8c45cf73b33e80d3ee4c64155336fb820d @@ -535,17 +535,17 @@ F src/pcache.h 4f87acd914cef5016fae3030343540d75f5b85a1877eed1a2a19b9f284248586 F src/pcache1.c 6596e10baf3d8f84cc1585d226cf1ab26564a5f5caf85a15757a281ff977d51a F src/pragma.c 6daaaecc26a4b09481d21722525b079ce756751a43a79cc1d8f122d686806193 F src/pragma.h 8dc78ab7e9ec6ce3ded8332810a2066f1ef6267e2e03cd7356ee00276125c6cf -F src/prepare.c a6bac9100b5f171189f6bb7ee12dfeeda7f3a8fd0c89be4a7958f14df13fa746 +F src/prepare.c 1f8bb4f20d83024194780f28920c6af9cfe52adc772ded8f33b4ee2b66f46f66 F src/printf.c 30e92b638fac71dcd85cdea1d12ecfae354c9adee2c71e8e1ae4727cde7c91ed F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384 F src/resolve.c 1948a92ca9eab776632816b97e57c61d933474a78aad4f4ef835c916a83dbb1c F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92 -F src/select.c 85c7cec9a4a983416d4bd023b2c4fbbeb608ae8dfb069781f80c8ed08b0c7a7c +F src/select.c b7281a798ee02cb356d2d8b7381939cb513646a91210478587ed6f7f33c357a8 F src/shell.c.in 79bceb990e4bac23a09bb8dd65783ea4867b8bfca9242b5a82b884043e65109a F src/sqlite.h.in 0af968a1fa3c717261e1df0ed105fa7bddb4d82de7e0adb3eab49e6aa81b4de7 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h 61b38c073d5e1e96a3d45271b257aef27d0d13da2bea5347692ae579475cd95e -F src/sqliteInt.h 0eb4c251a6df26fb97fcd0c285c5dd442f90f0d0305c14f2a9d0cfc006a0e1da +F src/sqliteInt.h e484ffb8ce2182ecd745b2e0af0caa12996e848b0f91748c742d1d135d31770c F src/sqliteLimit.h d7323ffea5208c6af2734574bae933ca8ed2ab728083caa117c9738581a31657 F src/status.c 4b8bc2a6905163a38b739854a35b826c737333fab5b1f8e03fa7eb9a4799c4c1 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1 @@ -604,9 +604,9 @@ F src/test_windirent.h 90dfbe95442c9762357fe128dc7ae3dc199d006de93eb33ba3972e0a9 F src/test_window.c cdae419fdcea5bad6dcd9368c685abdad6deb59e9fc8b84b153de513d394ba3f F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c -F src/tokenize.c 01dba3023659dc6f6b1e054c14b35a0074bd35de10466b99454d33278191d97f +F src/tokenize.c c64c49d7c2ec4490c2fef1f24350167ba16b03b0c6cee58ad1a1d70a4325d4e9 F src/treeview.c 4b92992176fb2caefbe06ba5bd06e0e0ebcde3d5564758da672631f17aa51cda -F src/trigger.c 515e79206d40d1d4149129318582e79a6e9db590a7b74e226fdb5b2a6c7e1b10 +F src/trigger.c 29680c54c1aa088fa1b4d50137d75669a40d5ef814394e321fab1e547868e3d3 F src/update.c 9f126204a6acb96bbe47391ae48e0fc579105d8e76a6d9c4fab3271367476580 F src/upsert.c df8f1727d62b5987c4fd302cd4d7c0c84ae57cd65683c5a34a740dfe24039235 F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0 @@ -1895,7 +1895,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 5204c2c4a7b73a64764b0d2d1d7c53709bb64e0d2685a829c7bf31af13bab5e7 -R 08e016b91a617b99baf0add20ffab4d1 +P 49dfce469e6a17111b349e53578479daf783064200bf0eec5bf8a91d3553b19f +R f1889156a8e996b56aa3e8cdd75a199d U drh -Z 8b24dd36b9adf4430f5fd36c021c9d5f +Z 2f77ed20cd8529f3498738d09cff4442 diff --git a/manifest.uuid b/manifest.uuid index ad74ba7a76..6b51da5c3c 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -49dfce469e6a17111b349e53578479daf783064200bf0eec5bf8a91d3553b19f \ No newline at end of file +affa2b7b316941b8a6c4d0d1ff212c81a593faf1d05d129e14d2b70d73a25c59 \ No newline at end of file diff --git a/src/insert.c b/src/insert.c index 0e52ee7a00..ae55868961 100644 --- a/src/insert.c +++ b/src/insert.c @@ -371,6 +371,7 @@ static int autoIncBegin( if( pInfo==0 ){ pInfo = sqlite3DbMallocRawNN(pParse->db, sizeof(*pInfo)); if( pInfo==0 ) return 0; + sqlite3ParserAddCleanup(pToplevel, sqlite3DbFreeNN, pInfo); pInfo->pNext = pToplevel->pAinc; pToplevel->pAinc = pInfo; pInfo->pTab = pTab; diff --git a/src/prepare.c b/src/prepare.c index 3a2943f103..980785c341 100644 --- a/src/prepare.c +++ b/src/prepare.c @@ -570,8 +570,16 @@ void sqlite3ParserReset(Parse *pParse){ agginfoFree(db, pThis); pThis = pNext; } + while( pParse->pCleanup ){ + ParseCleanup *pThis = pParse->pCleanup; + pParse->pCleanup = pThis->pNext; + pThis->xCleanup(db, pThis->pPtr); + sqlite3DbFree(db, pThis); + } sqlite3DbFree(db, pParse->aLabel); - sqlite3ExprListDelete(db, pParse->pConstExpr); + if( pParse->pConstExpr ){ + sqlite3ExprListDelete(db, pParse->pConstExpr); + } if( db ){ assert( db->lookaside.bDisable >= pParse->disableLookaside ); db->lookaside.bDisable -= pParse->disableLookaside; @@ -580,6 +588,34 @@ void sqlite3ParserReset(Parse *pParse){ pParse->disableLookaside = 0; } +/* +** Add a new cleanup operation to a Parser. The cleanup should happen when +** the parser object is destroyed. +** +** Use this mechanism for uncommon cleanups. There is a higher setup +** cost, so this should not be used for common cleanups. But for less +** common cleanups, we save a single NULL-pointer comparison in +** sqlite3ParserReset(), which makes a surprising difference in total +** performance. +** +** If a memory allocation error occurs, then the cleanup happens immediately. +*/ +void sqlite3ParserAddCleanup( + Parse *pParse, + void (*xCleanup)(sqlite3*,void*), + void *pPtr +){ + ParseCleanup *pCleanup = sqlite3DbMallocRaw(pParse->db, sizeof(*pCleanup)); + if( pCleanup ){ + pCleanup->pNext = pParse->pCleanup; + pParse->pCleanup = pCleanup; + pCleanup->pPtr = pPtr; + pCleanup->xCleanup = xCleanup; + }else{ + xCleanup(pParse->db, pPtr); + } +} + /* ** Compile the UTF-8 encoded SQL statement zSql into a statement handle. */ diff --git a/src/select.c b/src/select.c index 407a6a4b2e..fc853210fa 100644 --- a/src/select.c +++ b/src/select.c @@ -4140,8 +4140,9 @@ static int flattenSubquery( Table *pTabToDel = pSubitem->pTab; if( pTabToDel->nTabRef==1 ){ Parse *pToplevel = sqlite3ParseToplevel(pParse); - pTabToDel->pNextZombie = pToplevel->pZombieTab; - pToplevel->pZombieTab = pTabToDel; + sqlite3ParserAddCleanup(pToplevel, + (void(*)(sqlite3*,void*))sqlite3DeleteTable, + pTabToDel); }else{ pTabToDel->nTabRef--; } @@ -4856,12 +4857,15 @@ static struct Cte *searchWith( ** statement with which it is associated. */ void sqlite3WithPush(Parse *pParse, With *pWith, u8 bFree){ - assert( bFree==0 || (pParse->pWith==0 && pParse->pWithToFree==0) ); if( pWith ){ assert( pParse->pWith!=pWith ); pWith->pOuter = pParse->pWith; pParse->pWith = pWith; - if( bFree ) pParse->pWithToFree = pWith; + if( bFree ){ + sqlite3ParserAddCleanup(pParse, + (void(*)(sqlite3*,void*))sqlite3WithDelete, + pWith); + } } } diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 980ae6d580..484d63c5b8 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -1154,6 +1154,7 @@ typedef struct LookasideSlot LookasideSlot; typedef struct Module Module; typedef struct NameContext NameContext; typedef struct Parse Parse; +typedef struct ParseCleanup ParseCleanup; typedef struct PreUpdate PreUpdate; typedef struct PrintfArguments PrintfArguments; typedef struct RenameToken RenameToken; @@ -2186,7 +2187,6 @@ struct Table { #endif Trigger *pTrigger; /* List of triggers stored in pSchema */ Schema *pSchema; /* Schema that contains this table */ - Table *pNextZombie; /* Next on the Parse.pZombieTab list */ }; /* @@ -3348,6 +3348,17 @@ struct TriggerPrg { # define DbMaskNonZero(M) (M)!=0 #endif +/* +** An instance of the ParseCleanup object specifies an operation that +** should be performed after parsing to deallocation resources obtained +** during the parse and which are no longer needed. +*/ +struct ParseCleanup { + ParseCleanup *pNext; /* Next cleanup task */ + void *pPtr; /* Pointer to object to deallocate */ + void (*xCleanup)(sqlite3*,void*); /* Deallocation routine */ +}; + /* ** An SQL parser context. A copy of this structure is passed through ** the parser and down into all the parser action routine in order to @@ -3457,10 +3468,9 @@ struct Parse { Token sArg; /* Complete text of a module argument */ Table **apVtabLock; /* Pointer to virtual tables needing locking */ #endif - Table *pZombieTab; /* List of Table objects to delete after code gen */ TriggerPrg *pTriggerPrg; /* Linked list of coded triggers */ With *pWith; /* Current WITH clause, or NULL */ - With *pWithToFree; /* Free this WITH object at the end of the parse */ + ParseCleanup *pCleanup; /* List of cleanup operations to run after parse */ #ifndef SQLITE_OMIT_ALTERTABLE RenameToken *pRename; /* Tokens subject to renaming by ALTER TABLE */ #endif @@ -4827,6 +4837,7 @@ sqlite3_int64 sqlite3StmtCurrentTime(sqlite3_context*); int sqlite3VdbeParameterIndex(Vdbe*, const char*, int); int sqlite3TransferBindings(sqlite3_stmt *, sqlite3_stmt *); void sqlite3ParserReset(Parse*); +void sqlite3ParserAddCleanup(Parse*,void(*)(sqlite3*,void*),void*); #ifdef SQLITE_ENABLE_NORMALIZE char *sqlite3Normalize(Vdbe*, const char*); #endif diff --git a/src/tokenize.c b/src/tokenize.c index bafda0322b..712447c4ca 100644 --- a/src/tokenize.c +++ b/src/tokenize.c @@ -713,19 +713,7 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){ if( !IN_RENAME_OBJECT ){ sqlite3DeleteTrigger(db, pParse->pNewTrigger); } - - if( pParse->pWithToFree ) sqlite3WithDelete(db, pParse->pWithToFree); sqlite3DbFree(db, pParse->pVList); - while( pParse->pAinc ){ - AutoincInfo *p = pParse->pAinc; - pParse->pAinc = p->pNext; - sqlite3DbFreeNN(db, p); - } - while( pParse->pZombieTab ){ - Table *p = pParse->pZombieTab; - pParse->pZombieTab = p->pNextZombie; - sqlite3DeleteTable(db, p); - } db->pParse = pParse->pParentParse; pParse->pParentParse = 0; assert( nErr==0 || pParse->rc!=SQLITE_OK ); diff --git a/src/trigger.c b/src/trigger.c index dd4ed8c2e8..0c8cf5334f 100644 --- a/src/trigger.c +++ b/src/trigger.c @@ -1000,7 +1000,6 @@ static TriggerPrg *codeRowTrigger( sqlite3VdbeDelete(v); } - assert( !pSubParse->pAinc && !pSubParse->pZombieTab ); assert( !pSubParse->pTriggerPrg && !pSubParse->nMaxArg ); sqlite3ParserReset(pSubParse); sqlite3StackFree(db, pSubParse);