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*/ 22typedef struct sqlite3StatType sqlite3StatType; 23static 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*/ 46int 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*/ 56void 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*/ 68void 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*/ 84int 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*/ 100int 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 case SQLITE_DBSTATUS_LOOKASIDE_HIT: 120 case SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE: 121 case SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL: { 122 testcase( op==SQLITE_DBSTATUS_LOOKASIDE_HIT ); 123 testcase( op==SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE ); 124 testcase( op==SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL ); 125 assert( (op-SQLITE_DBSTATUS_LOOKASIDE_HIT)>=0 ); 126 assert( (op-SQLITE_DBSTATUS_LOOKASIDE_HIT)<3 ); 127 *pCurrent = 0; 128 *pHighwater = db->lookaside.anStat[op - SQLITE_DBSTATUS_LOOKASIDE_HIT]; 129 if( resetFlag ){ 130 db->lookaside.anStat[op - SQLITE_DBSTATUS_LOOKASIDE_HIT] = 0; 131 } 132 break; 133 } 134 135 /* 136 ** Return an approximation for the amount of memory currently used 137 ** by all pagers associated with the given database connection. The 138 ** highwater mark is meaningless and is returned as zero. 139 */ 140 case SQLITE_DBSTATUS_CACHE_USED: { 141 int totalUsed = 0; 142 int i; 143 sqlite3BtreeEnterAll(db); 144 for(i=0; i<db->nDb; i++){ 145 Btree *pBt = db->aDb[i].pBt; 146 if( pBt ){ 147 Pager *pPager = sqlite3BtreePager(pBt); 148 totalUsed += sqlite3PagerMemUsed(pPager); 149 } 150 } 151 sqlite3BtreeLeaveAll(db); 152 *pCurrent = totalUsed; 153 *pHighwater = 0; 154 break; 155 } 156 157 /* 158 ** *pCurrent gets an accurate estimate of the amount of memory used 159 ** to store the schema for all databases (main, temp, and any ATTACHed 160 ** databases. *pHighwater is set to zero. 161 */ 162 case SQLITE_DBSTATUS_SCHEMA_USED: { 163 int i; /* Used to iterate through schemas */ 164 int nByte = 0; /* Used to accumulate return value */ 165 166 sqlite3BtreeEnterAll(db); 167 db->pnBytesFreed = &nByte; 168 for(i=0; i<db->nDb; i++){ 169 Schema *pSchema = db->aDb[i].pSchema; 170 if( ALWAYS(pSchema!=0) ){ 171 HashElem *p; 172 173 nByte += sqlite3GlobalConfig.m.xRoundup(sizeof(HashElem)) * ( 174 pSchema->tblHash.count 175 + pSchema->trigHash.count 176 + pSchema->idxHash.count 177 + pSchema->fkeyHash.count 178 ); 179 nByte += sqlite3MallocSize(pSchema->tblHash.ht); 180 nByte += sqlite3MallocSize(pSchema->trigHash.ht); 181 nByte += sqlite3MallocSize(pSchema->idxHash.ht); 182 nByte += sqlite3MallocSize(pSchema->fkeyHash.ht); 183 184 for(p=sqliteHashFirst(&pSchema->trigHash); p; p=sqliteHashNext(p)){ 185 sqlite3DeleteTrigger(db, (Trigger*)sqliteHashData(p)); 186 } 187 for(p=sqliteHashFirst(&pSchema->tblHash); p; p=sqliteHashNext(p)){ 188 sqlite3DeleteTable(db, (Table *)sqliteHashData(p)); 189 } 190 } 191 } 192 db->pnBytesFreed = 0; 193 sqlite3BtreeLeaveAll(db); 194 195 *pHighwater = 0; 196 *pCurrent = nByte; 197 break; 198 } 199 200 /* 201 ** *pCurrent gets an accurate estimate of the amount of memory used 202 ** to store all prepared statements. 203 ** *pHighwater is set to zero. 204 */ 205 case SQLITE_DBSTATUS_STMT_USED: { 206 struct Vdbe *pVdbe; /* Used to iterate through VMs */ 207 int nByte = 0; /* Used to accumulate return value */ 208 209 db->pnBytesFreed = &nByte; 210 for(pVdbe=db->pVdbe; pVdbe; pVdbe=pVdbe->pNext){ 211 sqlite3VdbeDeleteObject(db, pVdbe); 212 } 213 db->pnBytesFreed = 0; 214 215 *pHighwater = 0; 216 *pCurrent = nByte; 217 218 break; 219 } 220 221 default: { 222 rc = SQLITE_ERROR; 223 } 224 } 225 sqlite3_mutex_leave(db->mutex); 226 return rc; 227} 228