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
This commit is contained in:
drh 2021-01-11 20:37:02 +00:00
parent a6e6cf2c8f
commit cf3c078f93
8 changed files with 72 additions and 33 deletions

View File

@ -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. 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-09T19:10:04.989 D 2021-01-11T20:37:02.868
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
@ -501,7 +501,7 @@ F src/hash.c 8d7dda241d0ebdafb6ffdeda3149a412d7df75102cecfc1021c98d6219823b19
F src/hash.h 9d56a9079d523b648774c1784b74b89bd93fac7b365210157482e4319a468f38 F src/hash.h 9d56a9079d523b648774c1784b74b89bd93fac7b365210157482e4319a468f38
F src/hwtime.h cb1d7e3e1ed94b7aa6fde95ae2c2daccc3df826be26fc9ed7fd90d1750ae6144 F src/hwtime.h cb1d7e3e1ed94b7aa6fde95ae2c2daccc3df826be26fc9ed7fd90d1750ae6144
F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71 F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
F src/insert.c 81b7ee72cd754b5d0018659d5593355f2d61b3d80f07f200167c4826846e907d F src/insert.c 9ced988440d29531568bfe4f48c7b69035b100f6833ca1080abb710b7c415111
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
F src/loadext.c 8c9c8cd2bd8eecdb06d9b6e89de7e9e65bae45cc8fc33609cc74023a5c296067 F src/loadext.c 8c9c8cd2bd8eecdb06d9b6e89de7e9e65bae45cc8fc33609cc74023a5c296067
F src/main.c 97e9f137354bc1f76dc9bb60a0a24f8c45cf73b33e80d3ee4c64155336fb820d F src/main.c 97e9f137354bc1f76dc9bb60a0a24f8c45cf73b33e80d3ee4c64155336fb820d
@ -535,17 +535,17 @@ F src/pcache.h 4f87acd914cef5016fae3030343540d75f5b85a1877eed1a2a19b9f284248586
F src/pcache1.c 6596e10baf3d8f84cc1585d226cf1ab26564a5f5caf85a15757a281ff977d51a F src/pcache1.c 6596e10baf3d8f84cc1585d226cf1ab26564a5f5caf85a15757a281ff977d51a
F src/pragma.c 6daaaecc26a4b09481d21722525b079ce756751a43a79cc1d8f122d686806193 F src/pragma.c 6daaaecc26a4b09481d21722525b079ce756751a43a79cc1d8f122d686806193
F src/pragma.h 8dc78ab7e9ec6ce3ded8332810a2066f1ef6267e2e03cd7356ee00276125c6cf F src/pragma.h 8dc78ab7e9ec6ce3ded8332810a2066f1ef6267e2e03cd7356ee00276125c6cf
F src/prepare.c a6bac9100b5f171189f6bb7ee12dfeeda7f3a8fd0c89be4a7958f14df13fa746 F src/prepare.c 1f8bb4f20d83024194780f28920c6af9cfe52adc772ded8f33b4ee2b66f46f66
F src/printf.c 30e92b638fac71dcd85cdea1d12ecfae354c9adee2c71e8e1ae4727cde7c91ed F src/printf.c 30e92b638fac71dcd85cdea1d12ecfae354c9adee2c71e8e1ae4727cde7c91ed
F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384 F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384
F src/resolve.c 1948a92ca9eab776632816b97e57c61d933474a78aad4f4ef835c916a83dbb1c F src/resolve.c 1948a92ca9eab776632816b97e57c61d933474a78aad4f4ef835c916a83dbb1c
F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92 F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92
F src/select.c 85c7cec9a4a983416d4bd023b2c4fbbeb608ae8dfb069781f80c8ed08b0c7a7c F src/select.c b7281a798ee02cb356d2d8b7381939cb513646a91210478587ed6f7f33c357a8
F src/shell.c.in 79bceb990e4bac23a09bb8dd65783ea4867b8bfca9242b5a82b884043e65109a F src/shell.c.in 79bceb990e4bac23a09bb8dd65783ea4867b8bfca9242b5a82b884043e65109a
F src/sqlite.h.in 0af968a1fa3c717261e1df0ed105fa7bddb4d82de7e0adb3eab49e6aa81b4de7 F src/sqlite.h.in 0af968a1fa3c717261e1df0ed105fa7bddb4d82de7e0adb3eab49e6aa81b4de7
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h 61b38c073d5e1e96a3d45271b257aef27d0d13da2bea5347692ae579475cd95e F src/sqlite3ext.h 61b38c073d5e1e96a3d45271b257aef27d0d13da2bea5347692ae579475cd95e
F src/sqliteInt.h 0eb4c251a6df26fb97fcd0c285c5dd442f90f0d0305c14f2a9d0cfc006a0e1da F src/sqliteInt.h e484ffb8ce2182ecd745b2e0af0caa12996e848b0f91748c742d1d135d31770c
F src/sqliteLimit.h d7323ffea5208c6af2734574bae933ca8ed2ab728083caa117c9738581a31657 F src/sqliteLimit.h d7323ffea5208c6af2734574bae933ca8ed2ab728083caa117c9738581a31657
F src/status.c 4b8bc2a6905163a38b739854a35b826c737333fab5b1f8e03fa7eb9a4799c4c1 F src/status.c 4b8bc2a6905163a38b739854a35b826c737333fab5b1f8e03fa7eb9a4799c4c1
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
@ -604,9 +604,9 @@ F src/test_windirent.h 90dfbe95442c9762357fe128dc7ae3dc199d006de93eb33ba3972e0a9
F src/test_window.c cdae419fdcea5bad6dcd9368c685abdad6deb59e9fc8b84b153de513d394ba3f F src/test_window.c cdae419fdcea5bad6dcd9368c685abdad6deb59e9fc8b84b153de513d394ba3f
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c
F src/tokenize.c 01dba3023659dc6f6b1e054c14b35a0074bd35de10466b99454d33278191d97f F src/tokenize.c c64c49d7c2ec4490c2fef1f24350167ba16b03b0c6cee58ad1a1d70a4325d4e9
F src/treeview.c 4b92992176fb2caefbe06ba5bd06e0e0ebcde3d5564758da672631f17aa51cda F src/treeview.c 4b92992176fb2caefbe06ba5bd06e0e0ebcde3d5564758da672631f17aa51cda
F src/trigger.c 515e79206d40d1d4149129318582e79a6e9db590a7b74e226fdb5b2a6c7e1b10 F src/trigger.c 29680c54c1aa088fa1b4d50137d75669a40d5ef814394e321fab1e547868e3d3
F src/update.c 9f126204a6acb96bbe47391ae48e0fc579105d8e76a6d9c4fab3271367476580 F src/update.c 9f126204a6acb96bbe47391ae48e0fc579105d8e76a6d9c4fab3271367476580
F src/upsert.c df8f1727d62b5987c4fd302cd4d7c0c84ae57cd65683c5a34a740dfe24039235 F src/upsert.c df8f1727d62b5987c4fd302cd4d7c0c84ae57cd65683c5a34a740dfe24039235
F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0 F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0
@ -1895,7 +1895,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 5204c2c4a7b73a64764b0d2d1d7c53709bb64e0d2685a829c7bf31af13bab5e7 P 49dfce469e6a17111b349e53578479daf783064200bf0eec5bf8a91d3553b19f
R 08e016b91a617b99baf0add20ffab4d1 R f1889156a8e996b56aa3e8cdd75a199d
U drh U drh
Z 8b24dd36b9adf4430f5fd36c021c9d5f Z 2f77ed20cd8529f3498738d09cff4442

View File

@ -1 +1 @@
49dfce469e6a17111b349e53578479daf783064200bf0eec5bf8a91d3553b19f affa2b7b316941b8a6c4d0d1ff212c81a593faf1d05d129e14d2b70d73a25c59

View File

@ -371,6 +371,7 @@ static int autoIncBegin(
if( pInfo==0 ){ if( pInfo==0 ){
pInfo = sqlite3DbMallocRawNN(pParse->db, sizeof(*pInfo)); pInfo = sqlite3DbMallocRawNN(pParse->db, sizeof(*pInfo));
if( pInfo==0 ) return 0; if( pInfo==0 ) return 0;
sqlite3ParserAddCleanup(pToplevel, sqlite3DbFreeNN, pInfo);
pInfo->pNext = pToplevel->pAinc; pInfo->pNext = pToplevel->pAinc;
pToplevel->pAinc = pInfo; pToplevel->pAinc = pInfo;
pInfo->pTab = pTab; pInfo->pTab = pTab;

View File

@ -570,8 +570,16 @@ void sqlite3ParserReset(Parse *pParse){
agginfoFree(db, pThis); agginfoFree(db, pThis);
pThis = pNext; 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); sqlite3DbFree(db, pParse->aLabel);
sqlite3ExprListDelete(db, pParse->pConstExpr); if( pParse->pConstExpr ){
sqlite3ExprListDelete(db, pParse->pConstExpr);
}
if( db ){ if( db ){
assert( db->lookaside.bDisable >= pParse->disableLookaside ); assert( db->lookaside.bDisable >= pParse->disableLookaside );
db->lookaside.bDisable -= pParse->disableLookaside; db->lookaside.bDisable -= pParse->disableLookaside;
@ -580,6 +588,34 @@ void sqlite3ParserReset(Parse *pParse){
pParse->disableLookaside = 0; 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. ** Compile the UTF-8 encoded SQL statement zSql into a statement handle.
*/ */

View File

@ -4140,8 +4140,9 @@ static int flattenSubquery(
Table *pTabToDel = pSubitem->pTab; Table *pTabToDel = pSubitem->pTab;
if( pTabToDel->nTabRef==1 ){ if( pTabToDel->nTabRef==1 ){
Parse *pToplevel = sqlite3ParseToplevel(pParse); Parse *pToplevel = sqlite3ParseToplevel(pParse);
pTabToDel->pNextZombie = pToplevel->pZombieTab; sqlite3ParserAddCleanup(pToplevel,
pToplevel->pZombieTab = pTabToDel; (void(*)(sqlite3*,void*))sqlite3DeleteTable,
pTabToDel);
}else{ }else{
pTabToDel->nTabRef--; pTabToDel->nTabRef--;
} }
@ -4856,12 +4857,15 @@ static struct Cte *searchWith(
** statement with which it is associated. ** statement with which it is associated.
*/ */
void sqlite3WithPush(Parse *pParse, With *pWith, u8 bFree){ void sqlite3WithPush(Parse *pParse, With *pWith, u8 bFree){
assert( bFree==0 || (pParse->pWith==0 && pParse->pWithToFree==0) );
if( pWith ){ if( pWith ){
assert( pParse->pWith!=pWith ); assert( pParse->pWith!=pWith );
pWith->pOuter = pParse->pWith; pWith->pOuter = pParse->pWith;
pParse->pWith = pWith; pParse->pWith = pWith;
if( bFree ) pParse->pWithToFree = pWith; if( bFree ){
sqlite3ParserAddCleanup(pParse,
(void(*)(sqlite3*,void*))sqlite3WithDelete,
pWith);
}
} }
} }

View File

@ -1154,6 +1154,7 @@ typedef struct LookasideSlot LookasideSlot;
typedef struct Module Module; typedef struct Module Module;
typedef struct NameContext NameContext; typedef struct NameContext NameContext;
typedef struct Parse Parse; typedef struct Parse Parse;
typedef struct ParseCleanup ParseCleanup;
typedef struct PreUpdate PreUpdate; typedef struct PreUpdate PreUpdate;
typedef struct PrintfArguments PrintfArguments; typedef struct PrintfArguments PrintfArguments;
typedef struct RenameToken RenameToken; typedef struct RenameToken RenameToken;
@ -2186,7 +2187,6 @@ struct Table {
#endif #endif
Trigger *pTrigger; /* List of triggers stored in pSchema */ Trigger *pTrigger; /* List of triggers stored in pSchema */
Schema *pSchema; /* Schema that contains this table */ 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 # define DbMaskNonZero(M) (M)!=0
#endif #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 ** 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 ** 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 */ Token sArg; /* Complete text of a module argument */
Table **apVtabLock; /* Pointer to virtual tables needing locking */ Table **apVtabLock; /* Pointer to virtual tables needing locking */
#endif #endif
Table *pZombieTab; /* List of Table objects to delete after code gen */
TriggerPrg *pTriggerPrg; /* Linked list of coded triggers */ TriggerPrg *pTriggerPrg; /* Linked list of coded triggers */
With *pWith; /* Current WITH clause, or NULL */ 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 #ifndef SQLITE_OMIT_ALTERTABLE
RenameToken *pRename; /* Tokens subject to renaming by ALTER TABLE */ RenameToken *pRename; /* Tokens subject to renaming by ALTER TABLE */
#endif #endif
@ -4827,6 +4837,7 @@ sqlite3_int64 sqlite3StmtCurrentTime(sqlite3_context*);
int sqlite3VdbeParameterIndex(Vdbe*, const char*, int); int sqlite3VdbeParameterIndex(Vdbe*, const char*, int);
int sqlite3TransferBindings(sqlite3_stmt *, sqlite3_stmt *); int sqlite3TransferBindings(sqlite3_stmt *, sqlite3_stmt *);
void sqlite3ParserReset(Parse*); void sqlite3ParserReset(Parse*);
void sqlite3ParserAddCleanup(Parse*,void(*)(sqlite3*,void*),void*);
#ifdef SQLITE_ENABLE_NORMALIZE #ifdef SQLITE_ENABLE_NORMALIZE
char *sqlite3Normalize(Vdbe*, const char*); char *sqlite3Normalize(Vdbe*, const char*);
#endif #endif

View File

@ -713,19 +713,7 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
if( !IN_RENAME_OBJECT ){ if( !IN_RENAME_OBJECT ){
sqlite3DeleteTrigger(db, pParse->pNewTrigger); sqlite3DeleteTrigger(db, pParse->pNewTrigger);
} }
if( pParse->pWithToFree ) sqlite3WithDelete(db, pParse->pWithToFree);
sqlite3DbFree(db, pParse->pVList); 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; db->pParse = pParse->pParentParse;
pParse->pParentParse = 0; pParse->pParentParse = 0;
assert( nErr==0 || pParse->rc!=SQLITE_OK ); assert( nErr==0 || pParse->rc!=SQLITE_OK );

View File

@ -1000,7 +1000,6 @@ static TriggerPrg *codeRowTrigger(
sqlite3VdbeDelete(v); sqlite3VdbeDelete(v);
} }
assert( !pSubParse->pAinc && !pSubParse->pZombieTab );
assert( !pSubParse->pTriggerPrg && !pSubParse->nMaxArg ); assert( !pSubParse->pTriggerPrg && !pSubParse->nMaxArg );
sqlite3ParserReset(pSubParse); sqlite3ParserReset(pSubParse);
sqlite3StackFree(db, pSubParse); sqlite3StackFree(db, pSubParse);