Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Experimental code to measure memory consumed by database schemas and prepared statements. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | experimental |
Files: | files | file ages | folders |
SHA1: |
9aa30342f4de4eff630520ea8e07ad25 |
User & Date: | dan 2010-07-24 11:28:29.000 |
Context
2010-07-26
| ||
11:07 | Make sure all memory from sqlite3DbMalloc() is freed by sqlite3DbFree() and all memory from sqlite3_malloc() is freed by sqlite3_free(). (check-in: 629e38a8c9 user: drh tags: experimental) | |
2010-07-24
| ||
11:28 | Experimental code to measure memory consumed by database schemas and prepared statements. (check-in: 9aa30342f4 user: dan tags: experimental) | |
2010-07-23
| ||
22:26 | Fix a typo in the OS/2 vfs code. (check-in: a6bb2108bf user: drh tags: trunk) | |
Changes
Changes to src/analyze.c.
︙ | ︙ | |||
486 487 488 489 490 491 492 | return 0; } /* ** If the Index.aSample variable is not NULL, delete the aSample[] array ** and its contents. */ | | | | < | 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 | return 0; } /* ** If the Index.aSample variable is not NULL, delete the aSample[] array ** and its contents. */ void sqlite3DeleteIndexSamples(sqlite3 *db, Index *pIdx){ #ifdef SQLITE_ENABLE_STAT2 if( pIdx->aSample ){ int j; for(j=0; j<SQLITE_INDEX_SAMPLES; j++){ IndexSample *p = &pIdx->aSample[j]; if( p->eType==SQLITE_TEXT || p->eType==SQLITE_BLOB ){ sqlite3DbFree(db, p->u.z); } } sqlite3DbFree(db, pIdx->aSample); } #else UNUSED_PARAMETER(pIdx); #endif } /* |
︙ | ︙ | |||
538 539 540 541 542 543 544 | assert( db->aDb[iDb].pBt!=0 ); assert( sqlite3BtreeHoldsMutex(db->aDb[iDb].pBt) ); /* Clear any prior statistics */ for(i=sqliteHashFirst(&db->aDb[iDb].pSchema->idxHash);i;i=sqliteHashNext(i)){ Index *pIdx = sqliteHashData(i); sqlite3DefaultRowEst(pIdx); | | > | 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 | assert( db->aDb[iDb].pBt!=0 ); assert( sqlite3BtreeHoldsMutex(db->aDb[iDb].pBt) ); /* Clear any prior statistics */ for(i=sqliteHashFirst(&db->aDb[iDb].pSchema->idxHash);i;i=sqliteHashNext(i)){ Index *pIdx = sqliteHashData(i); sqlite3DefaultRowEst(pIdx); sqlite3DeleteIndexSamples(db, pIdx); pIdx->aSample = 0; } /* Check to make sure the sqlite_stat1 table exists */ sInfo.db = db; sInfo.zDatabase = db->aDb[iDb].zName; if( sqlite3FindTable(db, "sqlite_stat1", sInfo.zDatabase)==0 ){ return SQLITE_ERROR; |
︙ | ︙ |
Changes to src/build.c.
︙ | ︙ | |||
343 344 345 346 347 348 349 | } /* ** Reclaim the memory used by an index */ static void freeIndex(sqlite3 *db, Index *p){ #ifndef SQLITE_OMIT_ANALYZE | | < < < < < < < < < < < < < < < < < < | 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 | } /* ** Reclaim the memory used by an index */ static void freeIndex(sqlite3 *db, Index *p){ #ifndef SQLITE_OMIT_ANALYZE sqlite3DeleteIndexSamples(db, p); #endif sqlite3DbFree(db, p->zColAff); sqlite3DbFree(db, p); } /* ** For the index called zIdxName which is found in the database iDb, ** unlike that index from its Table then remove the index from ** the index hash table and free all memory structures associated ** with the index. */ void sqlite3UnlinkAndDeleteIndex(sqlite3 *db, int iDb, const char *zIdxName){ |
︙ | ︙ | |||
464 465 466 467 468 469 470 | ** This routine is called when a commit occurs. */ void sqlite3CommitInternalChanges(sqlite3 *db){ db->flags &= ~SQLITE_InternChanges; } /* | | > | < < | < < | < | | < > > > > > > > | | | 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 | ** This routine is called when a commit occurs. */ void sqlite3CommitInternalChanges(sqlite3 *db){ db->flags &= ~SQLITE_InternChanges; } /* ** Delete memory allocated for the column names of a table or view (the ** Table.aCol[] array). */ static void sqliteDeleteColumnNames(sqlite3 *db, Table *pTable){ int i; Column *pCol; assert( pTable!=0 ); if( (pCol = pTable->aCol)!=0 ){ for(i=0; i<pTable->nCol; i++, pCol++){ sqlite3DbFree(db, pCol->zName); sqlite3ExprDelete(db, pCol->pDflt); sqlite3DbFree(db, pCol->zDflt); sqlite3DbFree(db, pCol->zType); sqlite3DbFree(db, pCol->zColl); } sqlite3DbFree(db, pTable->aCol); } } /* ** Remove the memory data structures associated with the given ** Table. No changes are made to disk by this routine. ** ** This routine just deletes the data structure. It does not unlink ** the table data structure from the hash table. But it does destroy ** memory structures of the indices and foreign keys associated with ** the table. */ void sqlite3DeleteTable(sqlite3 *db, Table *pTable){ Index *pIndex, *pNext; assert( !pTable || pTable->nRef>0 ); /* Do not delete the table until the reference count reaches zero. */ if( !pTable ) return; if( ((!db || db->pnBytesFreed==0) && (--pTable->nRef)>0) ) return; /* Delete all indices associated with this table. */ for(pIndex = pTable->pIndex; pIndex; pIndex=pNext){ pNext = pIndex->pNext; assert( pIndex->pSchema==pTable->pSchema ); 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. */ sqlite3FkDelete(db, pTable); /* Delete the Table structure itself. */ sqliteDeleteColumnNames(db, pTable); sqlite3DbFree(db, pTable->zName); sqlite3DbFree(db, pTable->zColAff); sqlite3SelectDelete(db, pTable->pSelect); #ifndef SQLITE_OMIT_CHECK sqlite3ExprDelete(db, pTable->pCheck); #endif sqlite3VtabClear(db, pTable); |
︙ | ︙ | |||
1813 1814 1815 1816 1817 1818 1819 | */ static void sqliteViewResetAll(sqlite3 *db, int idx){ HashElem *i; if( !DbHasProperty(db, idx, DB_UnresetViews) ) return; for(i=sqliteHashFirst(&db->aDb[idx].pSchema->tblHash); i;i=sqliteHashNext(i)){ Table *pTab = sqliteHashData(i); if( pTab->pSelect ){ | | > > | 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 | */ static void sqliteViewResetAll(sqlite3 *db, int idx){ HashElem *i; if( !DbHasProperty(db, idx, DB_UnresetViews) ) return; for(i=sqliteHashFirst(&db->aDb[idx].pSchema->tblHash); i;i=sqliteHashNext(i)){ Table *pTab = sqliteHashData(i); if( pTab->pSelect ){ sqliteDeleteColumnNames(db, pTab); pTab->aCol = 0; pTab->nCol = 0; } } DbClearProperty(db, idx, DB_UnresetViews); } #else # define sqliteViewResetAll(A,B) #endif /* SQLITE_OMIT_VIEW */ |
︙ | ︙ |
Changes to src/fkey.c.
︙ | ︙ | |||
1154 1155 1156 1157 1158 1159 1160 | void sqlite3FkDelete(sqlite3 *db, Table *pTab){ FKey *pFKey; /* Iterator variable */ FKey *pNext; /* Copy of pFKey->pNextFrom */ for(pFKey=pTab->pFKey; pFKey; pFKey=pNext){ /* Remove the FK from the fkeyHash hash table. */ | > | | | | | | | | | | > > > > > > < < < < < | 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 | void sqlite3FkDelete(sqlite3 *db, Table *pTab){ FKey *pFKey; /* Iterator variable */ FKey *pNext; /* Copy of pFKey->pNextFrom */ for(pFKey=pTab->pFKey; pFKey; pFKey=pNext){ /* Remove the FK from the fkeyHash hash table. */ if( !db || db->pnBytesFreed==0 ){ if( pFKey->pPrevTo ){ pFKey->pPrevTo->pNextTo = pFKey->pNextTo; }else{ void *p = (void *)pFKey->pNextTo; const char *z = (p ? pFKey->pNextTo->zTo : pFKey->zTo); sqlite3HashInsert(&pTab->pSchema->fkeyHash, z, sqlite3Strlen30(z), p); } if( pFKey->pNextTo ){ 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. */ #ifndef SQLITE_OMIT_TRIGGER fkTriggerDelete(db, pFKey->apTrigger[0]); fkTriggerDelete(db, pFKey->apTrigger[1]); #endif pNext = pFKey->pNextFrom; sqlite3DbFree(db, pFKey); } } #endif /* ifndef SQLITE_OMIT_FOREIGN_KEY */ |
Changes to src/malloc.c.
︙ | ︙ | |||
451 452 453 454 455 456 457 | /* ** Free memory that might be associated with a particular database ** connection. */ void sqlite3DbFree(sqlite3 *db, void *p){ assert( db==0 || sqlite3_mutex_held(db->mutex) ); | > | > > > > > | 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 | /* ** Free memory that might be associated with a particular database ** connection. */ void sqlite3DbFree(sqlite3 *db, void *p){ assert( db==0 || sqlite3_mutex_held(db->mutex) ); if( db && db->pnBytesFreed ){ if( isLookaside(db, p) ){ *db->pnBytesFreed += db->lookaside.sz; }else{ *db->pnBytesFreed += sqlite3MallocSize(p); } }else if( isLookaside(db, p) ){ LookasideSlot *pBuf = (LookasideSlot*)p; pBuf->pNext = db->lookaside.pFree; db->lookaside.pFree = pBuf; db->lookaside.nOut--; }else{ assert( sqlite3MemdebugHasType(p, db ? (MEMTYPE_DB|MEMTYPE_HEAP) : MEMTYPE_HEAP) ); |
︙ | ︙ |
Changes to src/sqlite.h.in.
︙ | ︙ | |||
5248 5249 5250 5251 5252 5253 5254 | ** memory used by all pager caches associated with the database connection. ** ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_USED is always 0. ** </dd> ** </dl> */ #define SQLITE_DBSTATUS_LOOKASIDE_USED 0 #define SQLITE_DBSTATUS_CACHE_USED 1 | > > | | 5248 5249 5250 5251 5252 5253 5254 5255 5256 5257 5258 5259 5260 5261 5262 5263 5264 | ** memory used by all pager caches associated with the database connection. ** ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_USED is always 0. ** </dd> ** </dl> */ #define SQLITE_DBSTATUS_LOOKASIDE_USED 0 #define SQLITE_DBSTATUS_CACHE_USED 1 #define SQLITE_DBSTATUS_SCHEMA_USED 2 #define SQLITE_DBSTATUS_STMT_USED 3 #define SQLITE_DBSTATUS_MAX 3 /* Largest defined DBSTATUS */ /* ** CAPI3REF: Prepared Statement Status ** ** ^(Each prepared statement maintains various ** [SQLITE_STMTSTATUS_SORT | counters] that measure the number |
︙ | ︙ |
Changes to src/sqliteInt.h.
︙ | ︙ | |||
856 857 858 859 860 861 862 863 864 865 866 867 868 869 | int busyTimeout; /* Busy handler timeout, in msec */ Db aDbStatic[2]; /* Static space for the 2 default backends */ Savepoint *pSavepoint; /* List of active savepoints */ int nSavepoint; /* Number of non-transaction savepoints */ int nStatement; /* Number of nested statement-transactions */ u8 isTransactionSavepoint; /* True if the outermost savepoint is a TS */ i64 nDeferredCons; /* Net deferred constraints this transaction. */ #ifdef SQLITE_ENABLE_UNLOCK_NOTIFY /* The following variables are all protected by the STATIC_MASTER ** mutex, not by sqlite3.mutex. They are used by code in notify.c. ** ** When X.pUnlockConnection==Y, that means that X is waiting for Y to ** unlock so that it can proceed. | > > | 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 | int busyTimeout; /* Busy handler timeout, in msec */ Db aDbStatic[2]; /* Static space for the 2 default backends */ Savepoint *pSavepoint; /* List of active savepoints */ int nSavepoint; /* Number of non-transaction savepoints */ int nStatement; /* Number of nested statement-transactions */ u8 isTransactionSavepoint; /* True if the outermost savepoint is a TS */ 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 /* The following variables are all protected by the STATIC_MASTER ** mutex, not by sqlite3.mutex. They are used by code in notify.c. ** ** When X.pUnlockConnection==Y, that means that X is waiting for Y to ** unlock so that it can proceed. |
︙ | ︙ | |||
2904 2905 2906 2907 2908 2909 2910 | CollSeq *sqlite3GetCollSeq(sqlite3*, u8, CollSeq *, const char*); char sqlite3AffinityType(const char*); void sqlite3Analyze(Parse*, Token*, Token*); int sqlite3InvokeBusyHandler(BusyHandler*); int sqlite3FindDb(sqlite3*, Token*); int sqlite3FindDbName(sqlite3 *, const char *); int sqlite3AnalysisLoad(sqlite3*,int iDB); | | | 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 | CollSeq *sqlite3GetCollSeq(sqlite3*, u8, CollSeq *, const char*); char sqlite3AffinityType(const char*); void sqlite3Analyze(Parse*, Token*, Token*); int sqlite3InvokeBusyHandler(BusyHandler*); int sqlite3FindDb(sqlite3*, Token*); int sqlite3FindDbName(sqlite3 *, const char *); int sqlite3AnalysisLoad(sqlite3*,int iDB); void sqlite3DeleteIndexSamples(sqlite3*,Index*); void sqlite3DefaultRowEst(Index*); void sqlite3RegisterLikeFunctions(sqlite3*, int); int sqlite3IsLikeFunction(sqlite3*,Expr*,int*,char*); void sqlite3MinimumFileFormat(Parse*, int, int); void sqlite3SchemaFree(void *); Schema *sqlite3SchemaGet(sqlite3 *, Btree *); int sqlite3SchemaToIndex(sqlite3 *db, Schema *); |
︙ | ︙ |
Changes to src/status.c.
︙ | ︙ | |||
10 11 12 13 14 15 16 17 18 19 20 21 22 23 | ** ************************************************************************* ** ** This module implements the sqlite3_status() interface and related ** functionality. */ #include "sqliteInt.h" /* ** Variables in which to record status information. */ typedef struct sqlite3StatType sqlite3StatType; static SQLITE_WSD struct sqlite3StatType { int nowValue[9]; /* Current value */ | > | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | ** ************************************************************************* ** ** This module implements the sqlite3_status() interface and related ** functionality. */ #include "sqliteInt.h" #include "vdbeInt.h" /* ** Variables in which to record status information. */ typedef struct sqlite3StatType sqlite3StatType; static SQLITE_WSD struct sqlite3StatType { int nowValue[9]; /* Current value */ |
︙ | ︙ | |||
132 133 134 135 136 137 138 139 140 141 142 143 144 145 | } } sqlite3BtreeLeaveAll(db); *pCurrent = totalUsed; *pHighwater = 0; break; } default: { rc = SQLITE_ERROR; } } sqlite3_mutex_leave(db->mutex); return rc; } | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 | } } sqlite3BtreeLeaveAll(db); *pCurrent = totalUsed; *pHighwater = 0; 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: { rc = SQLITE_ERROR; } } sqlite3_mutex_leave(db->mutex); return rc; } |
Changes to src/test_malloc.c.
︙ | ︙ | |||
1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 | int getDbPointer(Tcl_Interp*, const char*, sqlite3**); static const struct { const char *zName; int op; } aOp[] = { { "SQLITE_DBSTATUS_LOOKASIDE_USED", SQLITE_DBSTATUS_LOOKASIDE_USED }, { "SQLITE_DBSTATUS_CACHE_USED", SQLITE_DBSTATUS_CACHE_USED }, }; Tcl_Obj *pResult; if( objc!=4 ){ Tcl_WrongNumArgs(interp, 1, objv, "PARAMETER RESETFLAG"); return TCL_ERROR; } if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; | > > | 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 | int getDbPointer(Tcl_Interp*, const char*, sqlite3**); static const struct { const char *zName; int op; } aOp[] = { { "SQLITE_DBSTATUS_LOOKASIDE_USED", SQLITE_DBSTATUS_LOOKASIDE_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; if( objc!=4 ){ Tcl_WrongNumArgs(interp, 1, objv, "PARAMETER RESETFLAG"); return TCL_ERROR; } if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; |
︙ | ︙ |
Changes to src/vdbe.h.
︙ | ︙ | |||
79 80 81 82 83 84 85 86 87 88 89 90 91 92 | struct SubProgram { VdbeOp *aOp; /* Array of opcodes for sub-program */ int nOp; /* Elements in aOp[] */ int nMem; /* Number of memory cells required */ int nCsr; /* Number of cursors required */ int nRef; /* Number of pointers to this structure */ void *token; /* id that may be used to recursive triggers */ }; /* ** A smaller version of VdbeOp used for the VdbeAddOpList() function because ** it takes up less space. */ struct VdbeOpList { | > | 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | struct SubProgram { VdbeOp *aOp; /* Array of opcodes for sub-program */ int nOp; /* Elements in aOp[] */ int nMem; /* Number of memory cells required */ int nCsr; /* Number of cursors required */ int nRef; /* Number of pointers to this structure */ void *token; /* id that may be used to recursive triggers */ SubProgram *pNext; /* Next sub-program already visited */ }; /* ** A smaller version of VdbeOp used for the VdbeAddOpList() function because ** it takes up less space. */ struct VdbeOpList { |
︙ | ︙ | |||
180 181 182 183 184 185 186 187 188 189 190 191 192 193 | void sqlite3VdbeChangeToNoop(Vdbe*, int addr, int N); void sqlite3VdbeChangeP4(Vdbe*, int addr, const char *zP4, int N); void sqlite3VdbeUsesBtree(Vdbe*, int); VdbeOp *sqlite3VdbeGetOp(Vdbe*, int); int sqlite3VdbeMakeLabel(Vdbe*); void sqlite3VdbeRunOnlyOnce(Vdbe*); void sqlite3VdbeDelete(Vdbe*); void sqlite3VdbeMakeReady(Vdbe*,int,int,int,int,int,int); int sqlite3VdbeFinalize(Vdbe*); void sqlite3VdbeResolveLabel(Vdbe*, int); int sqlite3VdbeCurrentAddr(Vdbe*); #ifdef SQLITE_DEBUG int sqlite3VdbeAssertMayAbort(Vdbe *, int); void sqlite3VdbeTrace(Vdbe*,FILE*); | > | 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 | void sqlite3VdbeChangeToNoop(Vdbe*, int addr, int N); void sqlite3VdbeChangeP4(Vdbe*, int addr, const char *zP4, int N); void sqlite3VdbeUsesBtree(Vdbe*, int); VdbeOp *sqlite3VdbeGetOp(Vdbe*, int); int sqlite3VdbeMakeLabel(Vdbe*); void sqlite3VdbeRunOnlyOnce(Vdbe*); void sqlite3VdbeDelete(Vdbe*); void sqlite3VdbeDeleteObject(sqlite3*,Vdbe*); void sqlite3VdbeMakeReady(Vdbe*,int,int,int,int,int,int); int sqlite3VdbeFinalize(Vdbe*); void sqlite3VdbeResolveLabel(Vdbe*, int); int sqlite3VdbeCurrentAddr(Vdbe*); #ifdef SQLITE_DEBUG int sqlite3VdbeAssertMayAbort(Vdbe *, int); void sqlite3VdbeTrace(Vdbe*,FILE*); |
︙ | ︙ |
Changes to src/vdbeaux.c.
︙ | ︙ | |||
569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 | */ static void freeEphemeralFunction(sqlite3 *db, FuncDef *pDef){ if( ALWAYS(pDef) && (pDef->flags & SQLITE_FUNC_EPHEM)!=0 ){ sqlite3DbFree(db, pDef); } } /* ** Delete a P4 value if necessary. */ static void freeP4(sqlite3 *db, int p4type, void *p4){ if( p4 ){ switch( p4type ){ case P4_REAL: case P4_INT64: case P4_MPRINTF: case P4_DYNAMIC: case P4_KEYINFO: case P4_INTARRAY: case P4_KEYINFO_HANDOFF: { sqlite3DbFree(db, p4); break; } case P4_VDBEFUNC: { VdbeFunc *pVdbeFunc = (VdbeFunc *)p4; freeEphemeralFunction(db, pVdbeFunc->pFunc); | > > > | | > > > > > > > > > > > > > | > | 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 | */ static void freeEphemeralFunction(sqlite3 *db, FuncDef *pDef){ if( ALWAYS(pDef) && (pDef->flags & SQLITE_FUNC_EPHEM)!=0 ){ sqlite3DbFree(db, pDef); } } static void vdbeFreeOpArray(sqlite3 *, Op *, int); /* ** Delete a P4 value if necessary. */ static void freeP4(sqlite3 *db, int p4type, void *p4){ if( p4 ){ assert( db ); switch( p4type ){ case P4_REAL: case P4_INT64: case P4_MPRINTF: case P4_DYNAMIC: case P4_KEYINFO: case P4_INTARRAY: case P4_KEYINFO_HANDOFF: { sqlite3DbFree(db, p4); break; } case P4_VDBEFUNC: { VdbeFunc *pVdbeFunc = (VdbeFunc *)p4; freeEphemeralFunction(db, pVdbeFunc->pFunc); if( db->pnBytesFreed==0 ) sqlite3VdbeDeleteAuxData(pVdbeFunc, 0); sqlite3DbFree(db, pVdbeFunc); break; } case P4_FUNCDEF: { freeEphemeralFunction(db, (FuncDef*)p4); break; } case P4_MEM: { sqlite3ValueFree((sqlite3_value*)p4); break; } case P4_VTAB : { if( db->pnBytesFreed==0 ) sqlite3VtabUnlock((VTable *)p4); break; } 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); } break; } } } } /* |
︙ | ︙ | |||
999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 | ** Release an array of N Mem elements */ static void releaseMemArray(Mem *p, int N){ if( p && N ){ Mem *pEnd; sqlite3 *db = p->db; u8 malloc_failed = db->mallocFailed; for(pEnd=&p[N]; p<pEnd; p++){ assert( (&p[1])==pEnd || p[0].db==p[1].db ); /* This block is really an inlined version of sqlite3VdbeMemRelease() ** that takes advantage of the fact that the memory cell value is ** being set to NULL after releasing any dynamic resources. ** | > > > > > | 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 | ** Release an array of N Mem elements */ static void releaseMemArray(Mem *p, int N){ if( p && N ){ Mem *pEnd; sqlite3 *db = p->db; 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++){ assert( (&p[1])==pEnd || p[0].db==p[1].db ); /* This block is really an inlined version of sqlite3VdbeMemRelease() ** that takes advantage of the fact that the memory cell value is ** being set to NULL after releasing any dynamic resources. ** |
︙ | ︙ | |||
2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 | if( pAux->xDelete ){ pAux->xDelete(pAux->pAux); } pAux->pAux = 0; } } } /* ** Delete an entire VDBE. */ void sqlite3VdbeDelete(Vdbe *p){ sqlite3 *db; if( NEVER(p==0) ) return; db = p->db; if( p->pPrev ){ p->pPrev->pNext = p->pNext; }else{ assert( db->pVdbe==p ); db->pVdbe = p->pNext; } if( p->pNext ){ p->pNext->pPrev = p->pPrev; } | > > > > > > > > > > > > > > > > > > < < < < < < < | | 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 | if( pAux->xDelete ){ pAux->xDelete(pAux->pAux); } pAux->pAux = 0; } } } /* ** 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. */ void sqlite3VdbeDelete(Vdbe *p){ sqlite3 *db; if( NEVER(p==0) ) return; db = p->db; if( p->pPrev ){ p->pPrev->pNext = p->pNext; }else{ assert( db->pVdbe==p ); db->pVdbe = p->pNext; } if( p->pNext ){ p->pNext->pPrev = p->pPrev; } p->magic = VDBE_MAGIC_DEAD; p->db = 0; sqlite3VdbeDeleteObject(db, p); } /* ** Make sure the cursor p is ready to read or write the row to which it ** was last positioned. Return an error code if an OOM fault or I/O error ** prevents us from positioning the cursor to its correct position. ** |
︙ | ︙ |
Changes to src/vtab.c.
︙ | ︙ | |||
218 219 220 221 222 223 224 | ** The reference count of the VTable structure associated with database ** connection db is decremented immediately (which may lead to the ** structure being xDisconnected and free). Any other VTable structures ** in the list are moved to the sqlite3.pDisconnect list of the associated ** database connection. */ void sqlite3VtabClear(sqlite3 *db, Table *p){ | | | 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 | ** The reference count of the VTable structure associated with database ** connection db is decremented immediately (which may lead to the ** structure being xDisconnected and free). Any other VTable structures ** in the list are moved to the sqlite3.pDisconnect list of the associated ** database connection. */ void sqlite3VtabClear(sqlite3 *db, Table *p){ if( !db || db->pnBytesFreed==0 ) vtabDisconnectAll(0, p); if( p->azModuleArg ){ int i; for(i=0; i<p->nModuleArg; i++){ sqlite3DbFree(db, p->azModuleArg[i]); } sqlite3DbFree(db, p->azModuleArg); } |
︙ | ︙ |
Changes to test/dbstatus.test.
︙ | ︙ | |||
38 39 40 41 42 43 44 45 | do_test dbstatus-1.2 { db eval { INSERT INTO t1 VALUES(zeroblob(9000)); } lindex [sqlite3_db_status db SQLITE_DBSTATUS_CACHE_USED 0] 1 } [expr {$BASESZ + 10*$PAGESZ}] finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 | do_test dbstatus-1.2 { db eval { INSERT INTO t1 VALUES(zeroblob(9000)); } lindex [sqlite3_db_status db SQLITE_DBSTATUS_CACHE_USED 0] 1 } [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 |