1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-07 02:42:48 +03:00

Experimental code to measure memory consumed by database schemas and prepared statements.

FossilOrigin-Name: 9aa30342f4de4eff630520ea8e07ad253d3f0877
This commit is contained in:
dan
2010-07-24 11:28:28 +00:00
parent 5419ee5f2f
commit d46def77db
14 changed files with 430 additions and 97 deletions

View File

@@ -1,8 +1,5 @@
-----BEGIN PGP SIGNED MESSAGE----- C Experimental\scode\sto\smeasure\smemory\sconsumed\sby\sdatabase\sschemas\sand\sprepared\sstatements.
Hash: SHA1 D 2010-07-24T11:28:29
C Fix\sa\stypo\sin\sthe\sOS/2\svfs\scode.
D 2010-07-23T22:26:21
F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
F Makefile.in ec08dc838fd8110fe24c92e5130bcd91cbb1ff2e F Makefile.in ec08dc838fd8110fe24c92e5130bcd91cbb1ff2e
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
@@ -110,7 +107,7 @@ F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
F sqlite3.1 6be1ad09113570e1fc8dcaff84c9b0b337db5ffc F sqlite3.1 6be1ad09113570e1fc8dcaff84c9b0b337db5ffc
F sqlite3.pc.in ae6f59a76e862f5c561eb32a380228a02afc3cad F sqlite3.pc.in ae6f59a76e862f5c561eb32a380228a02afc3cad
F src/alter.c 8dc27638e7e2553e80b2b621f232be5eb1e85ef3 F src/alter.c 8dc27638e7e2553e80b2b621f232be5eb1e85ef3
F src/analyze.c 4ffed15a35cb669920348365fe71ce4d8800dc28 F src/analyze.c 6c2bdb1d13138d084b14010cd9fef4ff34e0d313
F src/attach.c 17bec1f18254d9341369f20f90ba24ce35d20d10 F src/attach.c 17bec1f18254d9341369f20f90ba24ce35d20d10
F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34 F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34
F src/backup.c 51d83300fe0baee39405c416ceb19a58ed30a8ed F src/backup.c 51d83300fe0baee39405c416ceb19a58ed30a8ed
@@ -119,7 +116,7 @@ F src/btmutex.c 96a12f50f7a17475155971a241d85ec5171573ff
F src/btree.c 9a214e6141555b183216b73ace058c7a499cdbe2 F src/btree.c 9a214e6141555b183216b73ace058c7a499cdbe2
F src/btree.h dd83041eda10c17daf023257c1fc883b5f71f85a F src/btree.h dd83041eda10c17daf023257c1fc883b5f71f85a
F src/btreeInt.h b0c87f6725b06a0aa194a6d25d54b16ce9d6e291 F src/btreeInt.h b0c87f6725b06a0aa194a6d25d54b16ce9d6e291
F src/build.c 8ccdb8ff8e86cbf5b891d4b236e50a91e69732d3 F src/build.c fdf428a35c0bd6256373e7779f3744ad4c8ff2eb
F src/callback.c 4e565b7f387e3261a19ecaf0cbbdebfb91988ea4 F src/callback.c 4e565b7f387e3261a19ecaf0cbbdebfb91988ea4
F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
F src/ctime.c 4f3aadad62c6c9f0d4e5a96718516ac4e3c598df F src/ctime.c 4f3aadad62c6c9f0d4e5a96718516ac4e3c598df
@@ -127,7 +124,7 @@ F src/date.c 5dd8448a0bfea8d31fb14cff487d0c06ff8c8b20
F src/delete.c 7ed8a8c8b5f748ece92df173d7e0f7810c899ebd F src/delete.c 7ed8a8c8b5f748ece92df173d7e0f7810c899ebd
F src/expr.c 7490fc3b16414d1a45d5acadf559317f9244891f F src/expr.c 7490fc3b16414d1a45d5acadf559317f9244891f
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
F src/fkey.c 62eed881a26a93e576b8cfeedea91952c90a8666 F src/fkey.c cacfe3e24b311e4e089a9c470bdb73196af6f729
F src/func.c 0c28599430856631216b6c0131c51c89bf516026 F src/func.c 0c28599430856631216b6c0131c51c89bf516026
F src/global.c 02335177cf6946fe5525c6f0755cf181140debf3 F src/global.c 02335177cf6946fe5525c6f0755cf181140debf3
F src/hash.c 458488dcc159c301b8e7686280ab209f1fb915af F src/hash.c 458488dcc159c301b8e7686280ab209f1fb915af
@@ -139,7 +136,7 @@ F src/legacy.c a199d7683d60cef73089e892409113e69c23a99f
F src/lempar.c 7f026423f4d71d989e719a743f98a1cbd4e6d99e F src/lempar.c 7f026423f4d71d989e719a743f98a1cbd4e6d99e
F src/loadext.c 1c7a61ce1281041f437333f366a96aa0d29bb581 F src/loadext.c 1c7a61ce1281041f437333f366a96aa0d29bb581
F src/main.c a487fe90aecaccb142e4a6b738c7e26e99145bcd F src/main.c a487fe90aecaccb142e4a6b738c7e26e99145bcd
F src/malloc.c f8b9bcd134ebfc95103d6834882567e66176d455 F src/malloc.c d321131022bd83f95f871cde212ddb01ed217f2f
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645 F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
F src/mem1.c 89d4ea8d5cdd55635cbaa48ad53132af6294cbb2 F src/mem1.c 89d4ea8d5cdd55635cbaa48ad53132af6294cbb2
F src/mem2.c 2ee7bdacda8299b5a91cff9f7ee3e46573195c38 F src/mem2.c 2ee7bdacda8299b5a91cff9f7ee3e46573195c38
@@ -173,11 +170,11 @@ F src/resolve.c 1c0f32b64f8e3f555fe1f732f9d6f501a7f05706
F src/rowset.c 69afa95a97c524ba6faf3805e717b5b7ae85a697 F src/rowset.c 69afa95a97c524ba6faf3805e717b5b7ae85a697
F src/select.c 74fef1334bec27e606ef0b19e5c41cd0a639e69c F src/select.c 74fef1334bec27e606ef0b19e5c41cd0a639e69c
F src/shell.c fd4ccdb37c3b68de0623eb938a649e0990710714 F src/shell.c fd4ccdb37c3b68de0623eb938a649e0990710714
F src/sqlite.h.in 2585fc82c922f2772e201e60a76d5fd1ca18370e F src/sqlite.h.in 05469b38a929b31278c7ed30b3d3f4b4e17817b6
F src/sqlite3ext.h 69dfb8116af51b84a029cddb3b35062354270c89 F src/sqlite3ext.h 69dfb8116af51b84a029cddb3b35062354270c89
F src/sqliteInt.h 13819304fa198f4a3ff0e6aa8d3a94df662d2829 F src/sqliteInt.h 0ec613ec2fbb26a1f363425c945a22667d659af5
F src/sqliteLimit.h 196e2f83c3b444c4548fc1874f52f84fdbda40f3 F src/sqliteLimit.h 196e2f83c3b444c4548fc1874f52f84fdbda40f3
F src/status.c e2ad9f18c16209dab501e26020590fcebb2b751b F src/status.c ab77d17fbfe0ab800b3c54dd6853e30b1dc1634e
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
F src/tclsqlite.c ae1e4fb653c91ddad7e2534d209711a12604ccc4 F src/tclsqlite.c ae1e4fb653c91ddad7e2534d209711a12604ccc4
F src/test1.c ff3b4533fc4d78d1bff2ef831a5791db55096ed3 F src/test1.c ff3b4533fc4d78d1bff2ef831a5791db55096ed3
@@ -203,7 +200,7 @@ F src/test_intarray.c d879bbf8e4ce085ab966d1f3c896a7c8b4f5fc99
F src/test_intarray.h 489edb9068bb926583445cb02589344961054207 F src/test_intarray.h 489edb9068bb926583445cb02589344961054207
F src/test_journal.c 424a334cdfdc8a6f975abe3641440147bded3185 F src/test_journal.c 424a334cdfdc8a6f975abe3641440147bded3185
F src/test_loadext.c df586c27176e3c2cb2e099c78da67bf14379a56e F src/test_loadext.c df586c27176e3c2cb2e099c78da67bf14379a56e
F src/test_malloc.c 4ab85f2b8ae3a237f4e6557b0a641181a19ffab1 F src/test_malloc.c 76bce0d5846dbfc9f24a65efab781b1ffb441380
F src/test_mutex.c ce06b59aca168cd8c520b77159a24352a7469bd3 F src/test_mutex.c ce06b59aca168cd8c520b77159a24352a7469bd3
F src/test_onefile.c 40cf9e212a377a6511469384a64b01e6e34b2eec F src/test_onefile.c 40cf9e212a377a6511469384a64b01e6e34b2eec
F src/test_osinst.c f408c6a181f2fb04c56273afd5c3e1e82f60392c F src/test_osinst.c f408c6a181f2fb04c56273afd5c3e1e82f60392c
@@ -222,14 +219,14 @@ F src/utf.c 1baeeac91707a4df97ccc6141ec0f808278af685
F src/util.c 32aebf04c10e51ad3977a928b7416bed671b620b F src/util.c 32aebf04c10e51ad3977a928b7416bed671b620b
F src/vacuum.c 241a8386727c1497eba4955933356dfba6ff8c9f F src/vacuum.c 241a8386727c1497eba4955933356dfba6ff8c9f
F src/vdbe.c 6294de3327e09d14e9c06ecfd10e57c2d8e85307 F src/vdbe.c 6294de3327e09d14e9c06ecfd10e57c2d8e85307
F src/vdbe.h 471f6a3dcec4817ca33596fe7f6654d56c0e75f3 F src/vdbe.h 7c5de1c7e2e6bc1f301bb95297aeb5d1b8455764
F src/vdbeInt.h 19ebc8c2a2e938340051ee65af3f377fb99102d1 F src/vdbeInt.h 19ebc8c2a2e938340051ee65af3f377fb99102d1
F src/vdbeapi.c dc3138f10afbc95ed3c21dd25abb154504b1db9d F src/vdbeapi.c dc3138f10afbc95ed3c21dd25abb154504b1db9d
F src/vdbeaux.c 7f99c1f00e4b31e8b28d8a87ecc2322bb46ae99c F src/vdbeaux.c 9f18d228ee96b26e10f908f8f9597c700347df71
F src/vdbeblob.c 258a6010ba7a82b72b327fb24c55790655689256 F src/vdbeblob.c 258a6010ba7a82b72b327fb24c55790655689256
F src/vdbemem.c 5e579abf6532001dfbee0e640dc34eae897a9807 F src/vdbemem.c 5e579abf6532001dfbee0e640dc34eae897a9807
F src/vdbetrace.c 864cef96919323482ebd9986f2132435115e9cc2 F src/vdbetrace.c 864cef96919323482ebd9986f2132435115e9cc2
F src/vtab.c 4b09cb71090b8a9ce8fdc451816ed2bd62861dcc F src/vtab.c 74bc8e035f3762d3cab1498dbbf2117e798540a5
F src/wal.c 0925601f3299c2941a67c9cfff41ee710f70ca82 F src/wal.c 0925601f3299c2941a67c9cfff41ee710f70ca82
F src/wal.h 906c85760598b18584921fe08008435aa4eeeeb2 F src/wal.h 906c85760598b18584921fe08008435aa4eeeeb2
F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f
@@ -333,7 +330,7 @@ F test/createtab.test 199cf68f44e5d9e87a0b8afc7130fdeb4def3272
F test/cse.test 277350a26264495e86b1785f34d2d0c8600e021c F test/cse.test 277350a26264495e86b1785f34d2d0c8600e021c
F test/ctime.test 7bd009071e242aac4f18521581536b652b789a47 F test/ctime.test 7bd009071e242aac4f18521581536b652b789a47
F test/date.test 6354b883f922c38046a8efbad187cc95df6da023 F test/date.test 6354b883f922c38046a8efbad187cc95df6da023
F test/dbstatus.test 838447a0ecca1232675b025c0a518a9ef0f8057e F test/dbstatus.test 6e4c7a82053f8bd0e218a11f6675ea927b3b2afc
F test/default.test 6faf23ccb300114924353007795aa9a8ec0aa9dc F test/default.test 6faf23ccb300114924353007795aa9a8ec0aa9dc
F test/delete.test f7629d9eb245dfca170169cc5c7a735dec34aeb4 F test/delete.test f7629d9eb245dfca170169cc5c7a735dec34aeb4
F test/delete2.test 3a03f2cca1f9a67ec469915cb8babd6485db43fa F test/delete2.test 3a03f2cca1f9a67ec469915cb8babd6485db43fa
@@ -841,14 +838,10 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
P 54e5886d841af69c8fa965bbcd637441d4a398ba P a6bb2108bfb562a7067ef6150e43382736c0c4f5
R 691d9a52bb7cbfd5e8dcb9749da71253 R 5ce07ed2a0b02fd2492d8af031b47b67
U drh T *branch * experimental
Z 52e232c87c73a10044c307be36db6f45 T *sym-experimental *
-----BEGIN PGP SIGNATURE----- T -sym-trunk *
Version: GnuPG v1.4.6 (GNU/Linux) U dan
Z 4780c44291ffd7692ca32c6ddced636f
iD8DBQFMShcQoxKgR168RlERAmjGAJoCLXWaZ2DuRMaoWPWt76CoNmu7twCfbMSo
7kHJSzk9KhxmMxRjeT/UwcA=
=7tfR
-----END PGP SIGNATURE-----

View File

@@ -1 +1 @@
a6bb2108bfb562a7067ef6150e43382736c0c4f5 9aa30342f4de4eff630520ea8e07ad253d3f0877

View File

@@ -490,18 +490,17 @@ static int analysisLoader(void *pData, int argc, char **argv, char **NotUsed){
** If the Index.aSample variable is not NULL, delete the aSample[] array ** If the Index.aSample variable is not NULL, delete the aSample[] array
** and its contents. ** and its contents.
*/ */
void sqlite3DeleteIndexSamples(Index *pIdx){ void sqlite3DeleteIndexSamples(sqlite3 *db, Index *pIdx){
#ifdef SQLITE_ENABLE_STAT2 #ifdef SQLITE_ENABLE_STAT2
if( pIdx->aSample ){ if( pIdx->aSample ){
int j; int j;
for(j=0; j<SQLITE_INDEX_SAMPLES; j++){ for(j=0; j<SQLITE_INDEX_SAMPLES; j++){
IndexSample *p = &pIdx->aSample[j]; IndexSample *p = &pIdx->aSample[j];
if( p->eType==SQLITE_TEXT || p->eType==SQLITE_BLOB ){ if( p->eType==SQLITE_TEXT || p->eType==SQLITE_BLOB ){
sqlite3_free(p->u.z); sqlite3DbFree(db, p->u.z);
} }
} }
sqlite3DbFree(0, pIdx->aSample); sqlite3DbFree(db, pIdx->aSample);
pIdx->aSample = 0;
} }
#else #else
UNUSED_PARAMETER(pIdx); UNUSED_PARAMETER(pIdx);
@@ -542,7 +541,8 @@ int sqlite3AnalysisLoad(sqlite3 *db, int iDb){
for(i=sqliteHashFirst(&db->aDb[iDb].pSchema->idxHash);i;i=sqliteHashNext(i)){ for(i=sqliteHashFirst(&db->aDb[iDb].pSchema->idxHash);i;i=sqliteHashNext(i)){
Index *pIdx = sqliteHashData(i); Index *pIdx = sqliteHashData(i);
sqlite3DefaultRowEst(pIdx); sqlite3DefaultRowEst(pIdx);
sqlite3DeleteIndexSamples(pIdx); sqlite3DeleteIndexSamples(db, pIdx);
pIdx->aSample = 0;
} }
/* Check to make sure the sqlite_stat1 table exists */ /* Check to make sure the sqlite_stat1 table exists */

View File

@@ -347,30 +347,12 @@ Index *sqlite3FindIndex(sqlite3 *db, const char *zName, const char *zDb){
*/ */
static void freeIndex(sqlite3 *db, Index *p){ static void freeIndex(sqlite3 *db, Index *p){
#ifndef SQLITE_OMIT_ANALYZE #ifndef SQLITE_OMIT_ANALYZE
sqlite3DeleteIndexSamples(p); sqlite3DeleteIndexSamples(db, p);
#endif #endif
sqlite3DbFree(db, p->zColAff); sqlite3DbFree(db, p->zColAff);
sqlite3DbFree(db, p); sqlite3DbFree(db, p);
} }
/*
** Remove the given index from the index hash table, and free
** its memory structures.
**
** The index is removed from the database hash tables but
** it is not unlinked from the Table that it indexes.
** Unlinking from the Table must be done by the calling function.
*/
static void sqlite3DeleteIndex(sqlite3 *db, Index *p){
Index *pOld;
const char *zName = p->zName;
pOld = sqlite3HashInsert(&p->pSchema->idxHash, zName,
sqlite3Strlen30(zName), 0);
assert( pOld==0 || pOld==p );
freeIndex(db, p);
}
/* /*
** For the index called zIdxName which is found in the database iDb, ** For the index called zIdxName which is found in the database iDb,
** unlike that index from its Table then remove the index from ** unlike that index from its Table then remove the index from
@@ -468,9 +450,10 @@ void sqlite3CommitInternalChanges(sqlite3 *db){
} }
/* /*
** Clear the column names from a table or view. ** Delete memory allocated for the column names of a table or view (the
** Table.aCol[] array).
*/ */
static void sqliteResetColumnNames(sqlite3 *db, Table *pTable){ static void sqliteDeleteColumnNames(sqlite3 *db, Table *pTable){
int i; int i;
Column *pCol; Column *pCol;
assert( pTable!=0 ); assert( pTable!=0 );
@@ -484,8 +467,6 @@ static void sqliteResetColumnNames(sqlite3 *db, Table *pTable){
} }
sqlite3DbFree(db, pTable->aCol); sqlite3DbFree(db, pTable->aCol);
} }
pTable->aCol = 0;
pTable->nCol = 0;
} }
/* /*
@@ -500,21 +481,24 @@ static void sqliteResetColumnNames(sqlite3 *db, Table *pTable){
void sqlite3DeleteTable(sqlite3 *db, Table *pTable){ void sqlite3DeleteTable(sqlite3 *db, Table *pTable){
Index *pIndex, *pNext; Index *pIndex, *pNext;
if( pTable==0 ) return; assert( !pTable || pTable->nRef>0 );
/* Do not delete the table until the reference count reaches zero. */ /* Do not delete the table until the reference count reaches zero. */
pTable->nRef--; if( !pTable ) return;
if( pTable->nRef>0 ){ if( ((!db || db->pnBytesFreed==0) && (--pTable->nRef)>0) ) return;
return;
}
assert( pTable->nRef==0 );
/* Delete all indices associated with this table /* Delete all indices associated with this table. */
*/
for(pIndex = pTable->pIndex; pIndex; pIndex=pNext){ for(pIndex = pTable->pIndex; pIndex; pIndex=pNext){
pNext = pIndex->pNext; pNext = pIndex->pNext;
assert( pIndex->pSchema==pTable->pSchema ); assert( pIndex->pSchema==pTable->pSchema );
sqlite3DeleteIndex(db, pIndex); if( !db || db->pnBytesFreed==0 ){
char *zName = pIndex->zName;
TESTONLY ( Index *pOld = ) sqlite3HashInsert(
&pIndex->pSchema->idxHash, zName, sqlite3Strlen30(zName), 0
);
assert( pOld==pIndex || pOld==0 );
}
freeIndex(db, pIndex);
} }
/* Delete any foreign keys attached to this table. */ /* Delete any foreign keys attached to this table. */
@@ -522,7 +506,7 @@ void sqlite3DeleteTable(sqlite3 *db, Table *pTable){
/* Delete the Table structure itself. /* Delete the Table structure itself.
*/ */
sqliteResetColumnNames(db, pTable); sqliteDeleteColumnNames(db, pTable);
sqlite3DbFree(db, pTable->zName); sqlite3DbFree(db, pTable->zName);
sqlite3DbFree(db, pTable->zColAff); sqlite3DbFree(db, pTable->zColAff);
sqlite3SelectDelete(db, pTable->pSelect); sqlite3SelectDelete(db, pTable->pSelect);
@@ -1817,7 +1801,9 @@ static void sqliteViewResetAll(sqlite3 *db, int idx){
for(i=sqliteHashFirst(&db->aDb[idx].pSchema->tblHash); i;i=sqliteHashNext(i)){ for(i=sqliteHashFirst(&db->aDb[idx].pSchema->tblHash); i;i=sqliteHashNext(i)){
Table *pTab = sqliteHashData(i); Table *pTab = sqliteHashData(i);
if( pTab->pSelect ){ if( pTab->pSelect ){
sqliteResetColumnNames(db, pTab); sqliteDeleteColumnNames(db, pTab);
pTab->aCol = 0;
pTab->nCol = 0;
} }
} }
DbClearProperty(db, idx, DB_UnresetViews); DbClearProperty(db, idx, DB_UnresetViews);

View File

@@ -1158,16 +1158,23 @@ void sqlite3FkDelete(sqlite3 *db, Table *pTab){
for(pFKey=pTab->pFKey; pFKey; pFKey=pNext){ for(pFKey=pTab->pFKey; pFKey; pFKey=pNext){
/* Remove the FK from the fkeyHash hash table. */ /* Remove the FK from the fkeyHash hash table. */
if( !db || db->pnBytesFreed==0 ){
if( pFKey->pPrevTo ){ if( pFKey->pPrevTo ){
pFKey->pPrevTo->pNextTo = pFKey->pNextTo; pFKey->pPrevTo->pNextTo = pFKey->pNextTo;
}else{ }else{
void *data = (void *)pFKey->pNextTo; void *p = (void *)pFKey->pNextTo;
const char *z = (data ? pFKey->pNextTo->zTo : pFKey->zTo); const char *z = (p ? pFKey->pNextTo->zTo : pFKey->zTo);
sqlite3HashInsert(&pTab->pSchema->fkeyHash, z, sqlite3Strlen30(z), data); sqlite3HashInsert(&pTab->pSchema->fkeyHash, z, sqlite3Strlen30(z), p);
} }
if( pFKey->pNextTo ){ if( pFKey->pNextTo ){
pFKey->pNextTo->pPrevTo = pFKey->pPrevTo; pFKey->pNextTo->pPrevTo = pFKey->pPrevTo;
} }
}
/* EV: R-30323-21917 Each foreign key constraint in SQLite is
** classified as either immediate or deferred.
*/
assert( pFKey->isDeferred==0 || pFKey->isDeferred==1 );
/* Delete any triggers created to implement actions for this FK. */ /* Delete any triggers created to implement actions for this FK. */
#ifndef SQLITE_OMIT_TRIGGER #ifndef SQLITE_OMIT_TRIGGER
@@ -1175,11 +1182,6 @@ void sqlite3FkDelete(sqlite3 *db, Table *pTab){
fkTriggerDelete(db, pFKey->apTrigger[1]); fkTriggerDelete(db, pFKey->apTrigger[1]);
#endif #endif
/* EV: R-30323-21917 Each foreign key constraint in SQLite is
** classified as either immediate or deferred.
*/
assert( pFKey->isDeferred==0 || pFKey->isDeferred==1 );
pNext = pFKey->pNextFrom; pNext = pFKey->pNextFrom;
sqlite3DbFree(db, pFKey); sqlite3DbFree(db, pFKey);
} }

View File

@@ -455,7 +455,13 @@ void sqlite3_free(void *p){
*/ */
void sqlite3DbFree(sqlite3 *db, void *p){ void sqlite3DbFree(sqlite3 *db, void *p){
assert( db==0 || sqlite3_mutex_held(db->mutex) ); assert( db==0 || sqlite3_mutex_held(db->mutex) );
if( db && db->pnBytesFreed ){
if( isLookaside(db, p) ){ if( isLookaside(db, p) ){
*db->pnBytesFreed += db->lookaside.sz;
}else{
*db->pnBytesFreed += sqlite3MallocSize(p);
}
}else if( isLookaside(db, p) ){
LookasideSlot *pBuf = (LookasideSlot*)p; LookasideSlot *pBuf = (LookasideSlot*)p;
pBuf->pNext = db->lookaside.pFree; pBuf->pNext = db->lookaside.pFree;
db->lookaside.pFree = pBuf; db->lookaside.pFree = pBuf;

View File

@@ -5252,7 +5252,9 @@ int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg);
*/ */
#define SQLITE_DBSTATUS_LOOKASIDE_USED 0 #define SQLITE_DBSTATUS_LOOKASIDE_USED 0
#define SQLITE_DBSTATUS_CACHE_USED 1 #define SQLITE_DBSTATUS_CACHE_USED 1
#define SQLITE_DBSTATUS_MAX 1 /* Largest defined DBSTATUS */ #define SQLITE_DBSTATUS_SCHEMA_USED 2
#define SQLITE_DBSTATUS_STMT_USED 3
#define SQLITE_DBSTATUS_MAX 3 /* Largest defined DBSTATUS */
/* /*

View File

@@ -860,6 +860,8 @@ struct sqlite3 {
int nStatement; /* Number of nested statement-transactions */ int nStatement; /* Number of nested statement-transactions */
u8 isTransactionSavepoint; /* True if the outermost savepoint is a TS */ u8 isTransactionSavepoint; /* True if the outermost savepoint is a TS */
i64 nDeferredCons; /* Net deferred constraints this transaction. */ i64 nDeferredCons; /* Net deferred constraints this transaction. */
int *pnBytesFreed; /* If not NULL, increment this in DbFree() */
SubProgram *pSubProgram; /* List of sub-programs already visited*/
#ifdef SQLITE_ENABLE_UNLOCK_NOTIFY #ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
/* The following variables are all protected by the STATIC_MASTER /* The following variables are all protected by the STATIC_MASTER
@@ -2908,7 +2910,7 @@ int sqlite3InvokeBusyHandler(BusyHandler*);
int sqlite3FindDb(sqlite3*, Token*); int sqlite3FindDb(sqlite3*, Token*);
int sqlite3FindDbName(sqlite3 *, const char *); int sqlite3FindDbName(sqlite3 *, const char *);
int sqlite3AnalysisLoad(sqlite3*,int iDB); int sqlite3AnalysisLoad(sqlite3*,int iDB);
void sqlite3DeleteIndexSamples(Index*); void sqlite3DeleteIndexSamples(sqlite3*,Index*);
void sqlite3DefaultRowEst(Index*); void sqlite3DefaultRowEst(Index*);
void sqlite3RegisterLikeFunctions(sqlite3*, int); void sqlite3RegisterLikeFunctions(sqlite3*, int);
int sqlite3IsLikeFunction(sqlite3*,Expr*,int*,char*); int sqlite3IsLikeFunction(sqlite3*,Expr*,int*,char*);

View File

@@ -14,6 +14,7 @@
** functionality. ** functionality.
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
#include "vdbeInt.h"
/* /*
** Variables in which to record status information. ** Variables in which to record status information.
@@ -136,6 +137,66 @@ int sqlite3_db_status(
*pHighwater = 0; *pHighwater = 0;
break; break;
} }
case SQLITE_DBSTATUS_SCHEMA_USED: {
int i; /* Used to iterate through schemas */
int nByte = 0; /* Used to accumulate return value */
assert( db->pSubProgram==0 );
db->pnBytesFreed = &nByte;
for(i=0; i<db->nDb; i++){
Schema *pSchema = db->aDb[i].pSchema;
if( pSchema ){
HashElem *p;
nByte += sizeof(HashElem) * (
pSchema->tblHash.count
+ pSchema->trigHash.count
+ pSchema->idxHash.count
+ pSchema->fkeyHash.count
);
nByte += sqlite3MallocSize(pSchema->tblHash.ht);
nByte += sqlite3MallocSize(pSchema->trigHash.ht);
nByte += sqlite3MallocSize(pSchema->idxHash.ht);
nByte += sqlite3MallocSize(pSchema->fkeyHash.ht);
for(p=sqliteHashFirst(&pSchema->trigHash); p; p=sqliteHashNext(p)){
sqlite3DeleteTrigger(db, (Trigger*)sqliteHashData(p));
}
for(p=sqliteHashFirst(&pSchema->tblHash); p; p=sqliteHashNext(p)){
sqlite3DeleteTable(db, (Table *)sqliteHashData(p));
}
}
}
db->pnBytesFreed = 0;
*pHighwater = 0;
*pCurrent = nByte;
break;
}
case SQLITE_DBSTATUS_STMT_USED: {
struct Vdbe *pVdbe; /* Used to iterate through VMs */
int nByte = 0; /* Used to accumulate return value */
db->pnBytesFreed = &nByte;
for(pVdbe=db->pVdbe; pVdbe; pVdbe=pVdbe->pNext){
SubProgram *pSub, *pNext;
sqlite3VdbeDeleteObject(db, pVdbe);
for(pSub=db->pSubProgram; pSub; pSub=pNext){
pNext = pSub->pNext;
pSub->pNext = 0;
}
db->pSubProgram = 0;
}
db->pnBytesFreed = 0;
*pHighwater = 0;
*pCurrent = nByte;
break;
}
default: { default: {
rc = SQLITE_ERROR; rc = SQLITE_ERROR;
} }

View File

@@ -1288,6 +1288,8 @@ static int test_db_status(
} aOp[] = { } aOp[] = {
{ "SQLITE_DBSTATUS_LOOKASIDE_USED", SQLITE_DBSTATUS_LOOKASIDE_USED }, { "SQLITE_DBSTATUS_LOOKASIDE_USED", SQLITE_DBSTATUS_LOOKASIDE_USED },
{ "SQLITE_DBSTATUS_CACHE_USED", SQLITE_DBSTATUS_CACHE_USED }, { "SQLITE_DBSTATUS_CACHE_USED", SQLITE_DBSTATUS_CACHE_USED },
{ "SQLITE_DBSTATUS_SCHEMA_USED", SQLITE_DBSTATUS_SCHEMA_USED },
{ "SQLITE_DBSTATUS_STMT_USED", SQLITE_DBSTATUS_STMT_USED }
}; };
Tcl_Obj *pResult; Tcl_Obj *pResult;
if( objc!=4 ){ if( objc!=4 ){

View File

@@ -83,6 +83,7 @@ struct SubProgram {
int nCsr; /* Number of cursors required */ int nCsr; /* Number of cursors required */
int nRef; /* Number of pointers to this structure */ int nRef; /* Number of pointers to this structure */
void *token; /* id that may be used to recursive triggers */ void *token; /* id that may be used to recursive triggers */
SubProgram *pNext; /* Next sub-program already visited */
}; };
/* /*
@@ -184,6 +185,7 @@ VdbeOp *sqlite3VdbeGetOp(Vdbe*, int);
int sqlite3VdbeMakeLabel(Vdbe*); int sqlite3VdbeMakeLabel(Vdbe*);
void sqlite3VdbeRunOnlyOnce(Vdbe*); void sqlite3VdbeRunOnlyOnce(Vdbe*);
void sqlite3VdbeDelete(Vdbe*); void sqlite3VdbeDelete(Vdbe*);
void sqlite3VdbeDeleteObject(sqlite3*,Vdbe*);
void sqlite3VdbeMakeReady(Vdbe*,int,int,int,int,int,int); void sqlite3VdbeMakeReady(Vdbe*,int,int,int,int,int,int);
int sqlite3VdbeFinalize(Vdbe*); int sqlite3VdbeFinalize(Vdbe*);
void sqlite3VdbeResolveLabel(Vdbe*, int); void sqlite3VdbeResolveLabel(Vdbe*, int);

View File

@@ -573,11 +573,14 @@ static void freeEphemeralFunction(sqlite3 *db, FuncDef *pDef){
} }
} }
static void vdbeFreeOpArray(sqlite3 *, Op *, int);
/* /*
** Delete a P4 value if necessary. ** Delete a P4 value if necessary.
*/ */
static void freeP4(sqlite3 *db, int p4type, void *p4){ static void freeP4(sqlite3 *db, int p4type, void *p4){
if( p4 ){ if( p4 ){
assert( db );
switch( p4type ){ switch( p4type ){
case P4_REAL: case P4_REAL:
case P4_INT64: case P4_INT64:
@@ -592,7 +595,7 @@ static void freeP4(sqlite3 *db, int p4type, void *p4){
case P4_VDBEFUNC: { case P4_VDBEFUNC: {
VdbeFunc *pVdbeFunc = (VdbeFunc *)p4; VdbeFunc *pVdbeFunc = (VdbeFunc *)p4;
freeEphemeralFunction(db, pVdbeFunc->pFunc); freeEphemeralFunction(db, pVdbeFunc->pFunc);
sqlite3VdbeDeleteAuxData(pVdbeFunc, 0); if( db->pnBytesFreed==0 ) sqlite3VdbeDeleteAuxData(pVdbeFunc, 0);
sqlite3DbFree(db, pVdbeFunc); sqlite3DbFree(db, pVdbeFunc);
break; break;
} }
@@ -605,11 +608,25 @@ static void freeP4(sqlite3 *db, int p4type, void *p4){
break; break;
} }
case P4_VTAB : { case P4_VTAB : {
sqlite3VtabUnlock((VTable *)p4); if( db->pnBytesFreed==0 ) sqlite3VtabUnlock((VTable *)p4);
break; break;
} }
case P4_SUBPROGRAM : { case P4_SUBPROGRAM : {
if( db->pnBytesFreed ){
SubProgram *p = (SubProgram *)p4;
SubProgram *pDone;
for(pDone=db->pSubProgram; pDone; pDone=pDone->pNext){
if( pDone==p ) break;
}
if( !pDone ){
p->pNext = db->pSubProgram;
db->pSubProgram = p;
vdbeFreeOpArray(db, p->aOp, p->nOp);
sqlite3DbFree(db, p);
}
}else{
sqlite3VdbeProgramDelete(db, (SubProgram *)p4, 1); sqlite3VdbeProgramDelete(db, (SubProgram *)p4, 1);
}
break; break;
} }
} }
@@ -1003,6 +1020,11 @@ static void releaseMemArray(Mem *p, int N){
Mem *pEnd; Mem *pEnd;
sqlite3 *db = p->db; sqlite3 *db = p->db;
u8 malloc_failed = db->mallocFailed; u8 malloc_failed = db->mallocFailed;
if( db->pnBytesFreed ){
for(pEnd=&p[N]; p<pEnd; p++){
sqlite3DbFree(db, p->zMalloc);
}
}else
for(pEnd=&p[N]; p<pEnd; p++){ for(pEnd=&p[N]; p<pEnd; p++){
assert( (&p[1])==pEnd || p[0].db==p[1].db ); assert( (&p[1])==pEnd || p[0].db==p[1].db );
@@ -2335,6 +2357,24 @@ void sqlite3VdbeDeleteAuxData(VdbeFunc *pVdbeFunc, int mask){
} }
} }
/*
** Free all memory associated with the Vdbe passed as the second argument.
** The difference between this function and sqlite3VdbeDelete() is that
** VdbeDelete() also unlinks the Vdbe from the list of VMs associated with
** the database connection.
*/
void sqlite3VdbeDeleteObject(sqlite3 *db, Vdbe *p){
assert( p->db==0 || p->db==db );
releaseMemArray(p->aVar, p->nVar);
releaseMemArray(p->aColName, p->nResColumn*COLNAME_N);
vdbeFreeOpArray(db, p->aOp, p->nOp);
sqlite3DbFree(db, p->aLabel);
sqlite3DbFree(db, p->aColName);
sqlite3DbFree(db, p->zSql);
sqlite3DbFree(db, p->pFree);
sqlite3DbFree(db, p);
}
/* /*
** Delete an entire VDBE. ** Delete an entire VDBE.
*/ */
@@ -2352,16 +2392,9 @@ void sqlite3VdbeDelete(Vdbe *p){
if( p->pNext ){ if( p->pNext ){
p->pNext->pPrev = p->pPrev; p->pNext->pPrev = p->pPrev;
} }
releaseMemArray(p->aVar, p->nVar);
releaseMemArray(p->aColName, p->nResColumn*COLNAME_N);
vdbeFreeOpArray(db, p->aOp, p->nOp);
sqlite3DbFree(db, p->aLabel);
sqlite3DbFree(db, p->aColName);
sqlite3DbFree(db, p->zSql);
p->magic = VDBE_MAGIC_DEAD; p->magic = VDBE_MAGIC_DEAD;
sqlite3DbFree(db, p->pFree);
p->db = 0; p->db = 0;
sqlite3DbFree(db, p); sqlite3VdbeDeleteObject(db, p);
} }
/* /*

View File

@@ -222,7 +222,7 @@ void sqlite3VtabUnlockList(sqlite3 *db){
** database connection. ** database connection.
*/ */
void sqlite3VtabClear(sqlite3 *db, Table *p){ void sqlite3VtabClear(sqlite3 *db, Table *p){
vtabDisconnectAll(0, p); if( !db || db->pnBytesFreed==0 ) vtabDisconnectAll(0, p);
if( p->azModuleArg ){ if( p->azModuleArg ){
int i; int i;
for(i=0; i<p->nModuleArg; i++){ for(i=0; i<p->nModuleArg; i++){

View File

@@ -42,4 +42,248 @@ do_test dbstatus-1.2 {
lindex [sqlite3_db_status db SQLITE_DBSTATUS_CACHE_USED 0] 1 lindex [sqlite3_db_status db SQLITE_DBSTATUS_CACHE_USED 0] 1
} [expr {$BASESZ + 10*$PAGESZ}] } [expr {$BASESZ + 10*$PAGESZ}]
proc lookaside {db} {
expr { $::lookaside_buffer_size *
[lindex [sqlite3_db_status $db SQLITE_DBSTATUS_LOOKASIDE_USED 0] 1]
}
}
#---------------------------------------------------------------------------
# Run the dbstatus-2 and dbstatus-3 tests with a couple of different
# lookaside buffer sizes.
#
foreach ::lookaside_buffer_size {0 64 120} {
#-------------------------------------------------------------------------
# Tests for SQLITE_DBSTATUS_SCHEMA_USED.
#
# Each test in the following block works as follows. Each test uses a
# different database schema.
#
# 1. Open a connection to an empty database. Disable statement caching.
#
# 2. Execute the SQL to create the database schema. Measure the total
# heap and lookaside memory allocated by SQLite, and the memory
# allocated for the database schema according to sqlite3_db_status().
#
# 3. Drop all tables in the database schema. Measure the total memory
# and the schema memory again.
#
# 4. Repeat step 2.
#
# 5. Repeat step 3.
#
# Then test that:
#
# a) The difference in schema memory quantities in steps 2 and 3 is the
# same as the difference in total memory in steps 2 and 3.
#
# b) Step 4 reports the same amount of schema and total memory used as
# in step 2.
#
# c) Step 5 reports the same amount of schema and total memory used as
# in step 3.
#
foreach {tn schema} {
1 { CREATE TABLE t1(a, b) }
2 { CREATE TABLE t1(a PRIMARY KEY, b REFERENCES t1, c UNIQUE) }
3 {
CREATE TABLE t1(a, b);
CREATE INDEX i1 ON t1(a, b);
}
4 {
CREATE TABLE t1(a, b);
CREATE TABLE t2(c, d);
CREATE TRIGGER AFTER INSERT ON t1 BEGIN
INSERT INTO t2 VALUES(new.a, new.b);
SELECT * FROM t1, t2 WHERE a=c AND b=d GROUP BY b HAVING a>5 ORDER BY a;
END;
}
5 {
CREATE TABLE t1(a, b);
CREATE TABLE t2(c, d);
CREATE VIEW v1 AS SELECT * FROM t1 UNION SELECT * FROM t2;
}
6 {
CREATE TABLE t1(a, b);
CREATE INDEX i1 ON t1(a);
CREATE INDEX i2 ON t1(a,b);
CREATE INDEX i3 ON t1(b,b);
INSERT INTO t1 VALUES(randomblob(20), randomblob(25));
INSERT INTO t1 SELECT randomblob(20), randomblob(25) FROM t1;
INSERT INTO t1 SELECT randomblob(20), randomblob(25) FROM t1;
INSERT INTO t1 SELECT randomblob(20), randomblob(25) FROM t1;
ANALYZE;
}
7 {
CREATE TABLE t1(a, b);
CREATE TABLE t2(c, d);
CREATE VIEW v1 AS
SELECT * FROM t1
UNION
SELECT * FROM t2
UNION ALL
SELECT c||b, d||a FROM t2 LEFT OUTER JOIN t1 GROUP BY c, d
ORDER BY 1, 2
;
CREATE TRIGGER tr1 INSTEAD OF INSERT ON v1 BEGIN
SELECT * FROM v1;
UPDATE t1 SET a=5, b=(SELECT c FROM t2);
END;
SELECT * FROM v1;
}
} {
set tn "$::lookaside_buffer_size-$tn"
# Step 1.
db close
file delete -force test.db
sqlite3 db test.db
sqlite3_db_config_lookaside db 0 $::lookaside_buffer_size 500
db cache size 0
# Step 2.
execsql $schema
set nAlloc1 [lindex [sqlite3_status SQLITE_STATUS_MEMORY_USED 0] 1]
incr nAlloc1 [lookaside db]
set nSchema1 [lindex [sqlite3_db_status db SQLITE_DBSTATUS_SCHEMA_USED 0] 1]
# Step 3.
drop_all_tables
set nAlloc2 [lindex [sqlite3_status SQLITE_STATUS_MEMORY_USED 0] 1]
incr nAlloc2 [lookaside db]
set nSchema2 [lindex [sqlite3_db_status db SQLITE_DBSTATUS_SCHEMA_USED 0] 1]
# Step 4.
execsql $schema
set nAlloc3 [lindex [sqlite3_status SQLITE_STATUS_MEMORY_USED 0] 1]
incr nAlloc3 [lookaside db]
set nSchema3 [lindex [sqlite3_db_status db SQLITE_DBSTATUS_SCHEMA_USED 0] 1]
# Step 5.
drop_all_tables
set nAlloc4 [lindex [sqlite3_status SQLITE_STATUS_MEMORY_USED 0] 1]
incr nAlloc4 [lookaside db]
set nSchema4 [lindex [sqlite3_db_status db SQLITE_DBSTATUS_SCHEMA_USED 0] 1]
set nFree [expr {$nAlloc1-$nAlloc2}]
do_test dbstatus-2.$tn.a { expr {$nSchema1-$nSchema2} } $nFree
do_test dbstatus-2.$tn.b { list $nAlloc1 $nSchema1 } "$nAlloc3 $nSchema3"
do_test dbstatus-2.$tn.c { list $nAlloc2 $nSchema2 } "$nAlloc4 $nSchema4"
}
#-------------------------------------------------------------------------
# Tests for SQLITE_DBSTATUS_STMT_USED.
#
# Each test in the following block works as follows. Each test uses a
# different database schema.
#
# 1. Open a connection to an empty database. Initialized the database
# schema.
#
# 2. Prepare a bunch of SQL statements. Measure the total heap and
# lookaside memory allocated by SQLite, and the memory allocated
# for the prepared statements according to sqlite3_db_status().
#
# 3. Finalize all prepared statements Measure the total memory
# and the prepared statement memory again.
#
# 4. Repeat step 2.
#
# 5. Repeat step 3.
#
# Then test that:
#
# a) The difference in schema memory quantities in steps 2 and 3 is the
# same as the difference in total memory in steps 2 and 3.
#
# b) Step 4 reports the same amount of schema and total memory used as
# in step 2.
#
# c) Step 5 reports the same amount of schema and total memory used as
# in step 3.
#
foreach {tn schema statements} {
1 { CREATE TABLE t1(a, b) } {
SELECT * FROM t1;
INSERT INTO t1 VALUES(1, 2);
INSERT INTO t1 SELECT * FROM t1;
UPDATE t1 SET a=5;
DELETE FROM t1;
}
2 {
PRAGMA recursive_triggers = 1;
CREATE TABLE t1(a, b);
CREATE TRIGGER tr1 AFTER INSERT ON t1 WHEN (new.a>0) BEGIN
INSERT INTO t1 VALUES(new.a-1, new.b);
END;
} {
INSERT INTO t1 VALUES(5, 'x');
}
3 {
PRAGMA recursive_triggers = 1;
CREATE TABLE t1(a, b);
CREATE TABLE t2(a, b);
CREATE TRIGGER tr1 AFTER INSERT ON t1 WHEN (new.a>0) BEGIN
INSERT INTO t2 VALUES(new.a-1, new.b);
END;
CREATE TRIGGER tr2 AFTER INSERT ON t1 WHEN (new.a>0) BEGIN
INSERT INTO t1 VALUES(new.a-1, new.b);
END;
} {
INSERT INTO t1 VALUES(10, 'x');
}
4 {
CREATE TABLE t1(a, b);
} {
SELECT count(*) FROM t1 WHERE upper(a)='ABC';
}
} {
set tn "$::lookaside_buffer_size-$tn"
# Step 1.
db close
file delete -force test.db
sqlite3 db test.db
sqlite3_db_config_lookaside db 0 $::lookaside_buffer_size 500
db cache size 1000
execsql $schema
db cache flush
# Step 2.
execsql $statements
set nAlloc1 [lindex [sqlite3_status SQLITE_STATUS_MEMORY_USED 0] 1]
incr nAlloc1 [lookaside db]
set nStmt1 [lindex [sqlite3_db_status db SQLITE_DBSTATUS_STMT_USED 0] 1]
execsql $statements
# Step 3.
db cache flush
set nAlloc2 [lindex [sqlite3_status SQLITE_STATUS_MEMORY_USED 0] 1]
incr nAlloc3 [lookaside db]
set nStmt2 [lindex [sqlite3_db_status db SQLITE_DBSTATUS_STMT_USED 0] 1]
# Step 3.
execsql $statements
set nAlloc3 [lindex [sqlite3_status SQLITE_STATUS_MEMORY_USED 0] 1]
incr nAlloc3 [lookaside db]
set nStmt3 [lindex [sqlite3_db_status db SQLITE_DBSTATUS_STMT_USED 0] 1]
execsql $statements
# Step 4.
db cache flush
set nAlloc4 [lindex [sqlite3_status SQLITE_STATUS_MEMORY_USED 0] 1]
incr nAlloc4 [lookaside db]
set nStmt4 [lindex [sqlite3_db_status db SQLITE_DBSTATUS_STMT_USED 0] 1]
set nFree [expr {$nAlloc1-$nAlloc2}]
do_test dbstatus-3.$tn.a { list $nStmt2 } {0}
do_test dbstatus-3.$tn.b { list $nStmt1 } [list $nFree]
do_test dbstatus-3.$tn.c { list $nAlloc1 $nStmt1 } [list $nAlloc3 $nStmt3]
do_test dbstatus-3.$tn.d { list $nAlloc2 $nStmt2 } [list $nAlloc4 $nStmt4]
}
}
finish_test finish_test