1 /* 2 ** 2008 June 18 3 ** 4 ** The author disclaims copyright to this source code. In place of 5 ** a legal notice, here is a blessing: 6 ** 7 ** May you do good and not evil. 8 ** May you find forgiveness for yourself and forgive others. 9 ** May you share freely, never taking more than you give. 10 ** 11 ************************************************************************* 12 ** 13 ** This module implements the sqlite3_status() interface and related 14 ** functionality. 15 */ 16 #include "sqliteInt.h" 17 #include "vdbeInt.h" 18 19 /* 20 ** Variables in which to record status information. 21 */ 22 typedef struct sqlite3StatType sqlite3StatType; 23 static SQLITE_WSD struct sqlite3StatType { 24 int nowValue[10]; /* Current value */ 25 int mxValue[10]; /* Maximum value */ 26 } sqlite3Stat = { {0,}, {0,} }; 27 28 29 /* The "wsdStat" macro will resolve to the status information 30 ** state vector. If writable static data is unsupported on the target, 31 ** we have to locate the state vector at run-time. In the more common 32 ** case where writable static data is supported, wsdStat can refer directly 33 ** to the "sqlite3Stat" state vector declared above. 34 */ 35 #ifdef SQLITE_OMIT_WSD 36 # define wsdStatInit sqlite3StatType *x = &GLOBAL(sqlite3StatType,sqlite3Stat) 37 # define wsdStat x[0] 38 #else 39 # define wsdStatInit 40 # define wsdStat sqlite3Stat 41 #endif 42 43 /* 44 ** Return the current value of a status parameter. 45 */ 46 int sqlite3StatusValue(int op){ 47 wsdStatInit; 48 assert( op>=0 && op<ArraySize(wsdStat.nowValue) ); 49 return wsdStat.nowValue[op]; 50 } 51 52 /* 53 ** Add N to the value of a status record. It is assumed that the 54 ** caller holds appropriate locks. 55 */ 56 void sqlite3StatusAdd(int op, int N){ 57 wsdStatInit; 58 assert( op>=0 && op<ArraySize(wsdStat.nowValue) ); 59 wsdStat.nowValue[op] += N; 60 if( wsdStat.nowValue[op]>wsdStat.mxValue[op] ){ 61 wsdStat.mxValue[op] = wsdStat.nowValue[op]; 62 } 63 } 64 65 /* 66 ** Set the value of a status to X. 67 */ 68 void sqlite3StatusSet(int op, int X){ 69 wsdStatInit; 70 assert( op>=0 && op<ArraySize(wsdStat.nowValue) ); 71 wsdStat.nowValue[op] = X; 72 if( wsdStat.nowValue[op]>wsdStat.mxValue[op] ){ 73 wsdStat.mxValue[op] = wsdStat.nowValue[op]; 74 } 75 } 76 77 /* 78 ** Query status information. 79 ** 80 ** This implementation assumes that reading or writing an aligned 81 ** 32-bit integer is an atomic operation. If that assumption is not true, 82 ** then this routine is not threadsafe. 83 */ 84 int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag){ 85 wsdStatInit; 86 if( op<0 || op>=ArraySize(wsdStat.nowValue) ){ 87 return SQLITE_MISUSE_BKPT; 88 } 89 *pCurrent = wsdStat.nowValue[op]; 90 *pHighwater = wsdStat.mxValue[op]; 91 if( resetFlag ){ 92 wsdStat.mxValue[op] = wsdStat.nowValue[op]; 93 } 94 return SQLITE_OK; 95 } 96 97 /* 98 ** Query status information for a single database connection 99 */ 100 int sqlite3_db_status( 101 sqlite3 *db, /* The database connection whose status is desired */ 102 int op, /* Status verb */ 103 int *pCurrent, /* Write current value here */ 104 int *pHighwater, /* Write high-water mark here */ 105 int resetFlag /* Reset high-water mark if true */ 106 ){ 107 int rc = SQLITE_OK; /* Return code */ 108 sqlite3_mutex_enter(db->mutex); 109 switch( op ){ 110 case SQLITE_DBSTATUS_LOOKASIDE_USED: { 111 *pCurrent = db->lookaside.nOut; 112 *pHighwater = db->lookaside.mxOut; 113 if( resetFlag ){ 114 db->lookaside.mxOut = db->lookaside.nOut; 115 } 116 break; 117 } 118 119 /* 120 ** Return an approximation for the amount of memory currently used 121 ** by all pagers associated with the given database connection. The 122 ** highwater mark is meaningless and is returned as zero. 123 */ 124 case SQLITE_DBSTATUS_CACHE_USED: { 125 int totalUsed = 0; 126 int i; 127 sqlite3BtreeEnterAll(db); 128 for(i=0; i<db->nDb; i++){ 129 Btree *pBt = db->aDb[i].pBt; 130 if( pBt ){ 131 Pager *pPager = sqlite3BtreePager(pBt); 132 totalUsed += sqlite3PagerMemUsed(pPager); 133 } 134 } 135 sqlite3BtreeLeaveAll(db); 136 *pCurrent = totalUsed; 137 *pHighwater = 0; 138 break; 139 } 140 141 /* 142 ** *pCurrent gets an accurate estimate of the amount of memory used 143 ** to store the schema for all databases (main, temp, and any ATTACHed 144 ** databases. *pHighwater is set to zero. 145 */ 146 case SQLITE_DBSTATUS_SCHEMA_USED: { 147 int i; /* Used to iterate through schemas */ 148 int nByte = 0; /* Used to accumulate return value */ 149 150 db->pnBytesFreed = &nByte; 151 for(i=0; i<db->nDb; i++){ 152 Schema *pSchema = db->aDb[i].pSchema; 153 if( ALWAYS(pSchema!=0) ){ 154 HashElem *p; 155 156 nByte += sqlite3GlobalConfig.m.xRoundup(sizeof(HashElem)) * ( 157 pSchema->tblHash.count 158 + pSchema->trigHash.count 159 + pSchema->idxHash.count 160 + pSchema->fkeyHash.count 161 ); 162 nByte += sqlite3MallocSize(pSchema->tblHash.ht); 163 nByte += sqlite3MallocSize(pSchema->trigHash.ht); 164 nByte += sqlite3MallocSize(pSchema->idxHash.ht); 165 nByte += sqlite3MallocSize(pSchema->fkeyHash.ht); 166 167 for(p=sqliteHashFirst(&pSchema->trigHash); p; p=sqliteHashNext(p)){ 168 sqlite3DeleteTrigger(db, (Trigger*)sqliteHashData(p)); 169 } 170 for(p=sqliteHashFirst(&pSchema->tblHash); p; p=sqliteHashNext(p)){ 171 sqlite3DeleteTable(db, (Table *)sqliteHashData(p)); 172 } 173 } 174 } 175 db->pnBytesFreed = 0; 176 177 *pHighwater = 0; 178 *pCurrent = nByte; 179 break; 180 } 181 182 /* 183 ** *pCurrent gets an accurate estimate of the amount of memory used 184 ** to store all prepared statements. 185 ** *pHighwater is set to zero. 186 */ 187 case SQLITE_DBSTATUS_STMT_USED: { 188 struct Vdbe *pVdbe; /* Used to iterate through VMs */ 189 int nByte = 0; /* Used to accumulate return value */ 190 191 db->pnBytesFreed = &nByte; 192 for(pVdbe=db->pVdbe; pVdbe; pVdbe=pVdbe->pNext){ 193 sqlite3VdbeDeleteObject(db, pVdbe); 194 } 195 db->pnBytesFreed = 0; 196 197 *pHighwater = 0; 198 *pCurrent = nByte; 199 200 break; 201 } 202 203 default: { 204 rc = SQLITE_ERROR; 205 } 206 } 207 sqlite3_mutex_leave(db->mutex); 208 return rc; 209 } 210