xref: /sqlite-3.40.0/src/status.c (revision e5928b17)
1c4b18b82Sdrh /*
2c4b18b82Sdrh ** 2008 June 18
3c4b18b82Sdrh **
4c4b18b82Sdrh ** The author disclaims copyright to this source code.  In place of
5c4b18b82Sdrh ** a legal notice, here is a blessing:
6c4b18b82Sdrh **
7c4b18b82Sdrh **    May you do good and not evil.
8c4b18b82Sdrh **    May you find forgiveness for yourself and forgive others.
9c4b18b82Sdrh **    May you share freely, never taking more than you give.
10c4b18b82Sdrh **
11c4b18b82Sdrh *************************************************************************
12c4b18b82Sdrh **
13c4b18b82Sdrh ** This module implements the sqlite3_status() interface and related
14c4b18b82Sdrh ** functionality.
15c4b18b82Sdrh */
16c4b18b82Sdrh #include "sqliteInt.h"
17d46def77Sdan #include "vdbeInt.h"
18c4b18b82Sdrh 
19c4b18b82Sdrh /*
20c4b18b82Sdrh ** Variables in which to record status information.
21c4b18b82Sdrh */
227ef855f1Smistachkin #if SQLITE_PTRSIZE>4
237ef855f1Smistachkin typedef sqlite3_int64 sqlite3StatValueType;
247ef855f1Smistachkin #else
257ef855f1Smistachkin typedef u32 sqlite3StatValueType;
267ef855f1Smistachkin #endif
2778f82d1eSdrh typedef struct sqlite3StatType sqlite3StatType;
2878f82d1eSdrh static SQLITE_WSD struct sqlite3StatType {
297ef855f1Smistachkin   sqlite3StatValueType nowValue[10];  /* Current value */
307ef855f1Smistachkin   sqlite3StatValueType mxValue[10];   /* Maximum value */
3178f82d1eSdrh } sqlite3Stat = { {0,}, {0,} };
32c4b18b82Sdrh 
33af89fe66Sdrh /*
34af89fe66Sdrh ** Elements of sqlite3Stat[] are protected by either the memory allocator
35af89fe66Sdrh ** mutex, or by the pcache1 mutex.  The following array determines which.
36af89fe66Sdrh */
37af89fe66Sdrh static const char statMutex[] = {
38af89fe66Sdrh   0,  /* SQLITE_STATUS_MEMORY_USED */
39af89fe66Sdrh   1,  /* SQLITE_STATUS_PAGECACHE_USED */
40af89fe66Sdrh   1,  /* SQLITE_STATUS_PAGECACHE_OVERFLOW */
41af89fe66Sdrh   0,  /* SQLITE_STATUS_SCRATCH_USED */
42af89fe66Sdrh   0,  /* SQLITE_STATUS_SCRATCH_OVERFLOW */
43af89fe66Sdrh   0,  /* SQLITE_STATUS_MALLOC_SIZE */
44af89fe66Sdrh   0,  /* SQLITE_STATUS_PARSER_STACK */
45af89fe66Sdrh   1,  /* SQLITE_STATUS_PAGECACHE_SIZE */
46af89fe66Sdrh   0,  /* SQLITE_STATUS_SCRATCH_SIZE */
47af89fe66Sdrh   0,  /* SQLITE_STATUS_MALLOC_COUNT */
48af89fe66Sdrh };
49af89fe66Sdrh 
50c4b18b82Sdrh 
5178f82d1eSdrh /* The "wsdStat" macro will resolve to the status information
5278f82d1eSdrh ** state vector.  If writable static data is unsupported on the target,
5378f82d1eSdrh ** we have to locate the state vector at run-time.  In the more common
5478f82d1eSdrh ** case where writable static data is supported, wsdStat can refer directly
5578f82d1eSdrh ** to the "sqlite3Stat" state vector declared above.
5678f82d1eSdrh */
5778f82d1eSdrh #ifdef SQLITE_OMIT_WSD
5878f82d1eSdrh # define wsdStatInit  sqlite3StatType *x = &GLOBAL(sqlite3StatType,sqlite3Stat)
5978f82d1eSdrh # define wsdStat x[0]
6078f82d1eSdrh #else
6178f82d1eSdrh # define wsdStatInit
6278f82d1eSdrh # define wsdStat sqlite3Stat
6378f82d1eSdrh #endif
6478f82d1eSdrh 
65c4b18b82Sdrh /*
66af89fe66Sdrh ** Return the current value of a status parameter.  The caller must
67af89fe66Sdrh ** be holding the appropriate mutex.
68c4b18b82Sdrh */
sqlite3StatusValue(int op)69af89fe66Sdrh sqlite3_int64 sqlite3StatusValue(int op){
7078f82d1eSdrh   wsdStatInit;
7178f82d1eSdrh   assert( op>=0 && op<ArraySize(wsdStat.nowValue) );
72af89fe66Sdrh   assert( op>=0 && op<ArraySize(statMutex) );
73af89fe66Sdrh   assert( sqlite3_mutex_held(statMutex[op] ? sqlite3Pcache1Mutex()
74af89fe66Sdrh                                            : sqlite3MallocMutex()) );
7578f82d1eSdrh   return wsdStat.nowValue[op];
76c4b18b82Sdrh }
77c4b18b82Sdrh 
78c4b18b82Sdrh /*
79af89fe66Sdrh ** Add N to the value of a status record.  The caller must hold the
80af89fe66Sdrh ** appropriate mutex.  (Locking is checked by assert()).
81af89fe66Sdrh **
82af89fe66Sdrh ** The StatusUp() routine can accept positive or negative values for N.
83af89fe66Sdrh ** The value of N is added to the current status value and the high-water
84af89fe66Sdrh ** mark is adjusted if necessary.
85af89fe66Sdrh **
86af89fe66Sdrh ** The StatusDown() routine lowers the current value by N.  The highwater
87af89fe66Sdrh ** mark is unchanged.  N must be non-negative for StatusDown().
88c4b18b82Sdrh */
sqlite3StatusUp(int op,int N)89af89fe66Sdrh void sqlite3StatusUp(int op, int N){
9078f82d1eSdrh   wsdStatInit;
9178f82d1eSdrh   assert( op>=0 && op<ArraySize(wsdStat.nowValue) );
92af89fe66Sdrh   assert( op>=0 && op<ArraySize(statMutex) );
93af89fe66Sdrh   assert( sqlite3_mutex_held(statMutex[op] ? sqlite3Pcache1Mutex()
94af89fe66Sdrh                                            : sqlite3MallocMutex()) );
9578f82d1eSdrh   wsdStat.nowValue[op] += N;
9678f82d1eSdrh   if( wsdStat.nowValue[op]>wsdStat.mxValue[op] ){
9778f82d1eSdrh     wsdStat.mxValue[op] = wsdStat.nowValue[op];
98c4b18b82Sdrh   }
99c4b18b82Sdrh }
sqlite3StatusDown(int op,int N)100af89fe66Sdrh void sqlite3StatusDown(int op, int N){
101af89fe66Sdrh   wsdStatInit;
102af89fe66Sdrh   assert( N>=0 );
103af89fe66Sdrh   assert( op>=0 && op<ArraySize(statMutex) );
104af89fe66Sdrh   assert( sqlite3_mutex_held(statMutex[op] ? sqlite3Pcache1Mutex()
105af89fe66Sdrh                                            : sqlite3MallocMutex()) );
106af89fe66Sdrh   assert( op>=0 && op<ArraySize(wsdStat.nowValue) );
107af89fe66Sdrh   wsdStat.nowValue[op] -= N;
108af89fe66Sdrh }
109c4b18b82Sdrh 
110c4b18b82Sdrh /*
111b02392e6Sdrh ** Adjust the highwater mark if necessary.
112b02392e6Sdrh ** The caller must hold the appropriate mutex.
113c4b18b82Sdrh */
sqlite3StatusHighwater(int op,int X)114b02392e6Sdrh void sqlite3StatusHighwater(int op, int X){
1157ef855f1Smistachkin   sqlite3StatValueType newValue;
11678f82d1eSdrh   wsdStatInit;
1177ef855f1Smistachkin   assert( X>=0 );
1187ef855f1Smistachkin   newValue = (sqlite3StatValueType)X;
11978f82d1eSdrh   assert( op>=0 && op<ArraySize(wsdStat.nowValue) );
120af89fe66Sdrh   assert( op>=0 && op<ArraySize(statMutex) );
121af89fe66Sdrh   assert( sqlite3_mutex_held(statMutex[op] ? sqlite3Pcache1Mutex()
122af89fe66Sdrh                                            : sqlite3MallocMutex()) );
123b02392e6Sdrh   assert( op==SQLITE_STATUS_MALLOC_SIZE
124b02392e6Sdrh           || op==SQLITE_STATUS_PAGECACHE_SIZE
125b02392e6Sdrh           || op==SQLITE_STATUS_PARSER_STACK );
1267ef855f1Smistachkin   if( newValue>wsdStat.mxValue[op] ){
1277ef855f1Smistachkin     wsdStat.mxValue[op] = newValue;
128c4b18b82Sdrh   }
129c4b18b82Sdrh }
130c4b18b82Sdrh 
131c4b18b82Sdrh /*
132c4b18b82Sdrh ** Query status information.
133c4b18b82Sdrh */
sqlite3_status64(int op,sqlite3_int64 * pCurrent,sqlite3_int64 * pHighwater,int resetFlag)134af89fe66Sdrh int sqlite3_status64(
135af89fe66Sdrh   int op,
136af89fe66Sdrh   sqlite3_int64 *pCurrent,
137af89fe66Sdrh   sqlite3_int64 *pHighwater,
138af89fe66Sdrh   int resetFlag
139af89fe66Sdrh ){
140af89fe66Sdrh   sqlite3_mutex *pMutex;
1412493870dSdrh   wsdStatInit;
14278f82d1eSdrh   if( op<0 || op>=ArraySize(wsdStat.nowValue) ){
143413c3d36Sdrh     return SQLITE_MISUSE_BKPT;
144c4b18b82Sdrh   }
1459ca95730Sdrh #ifdef SQLITE_ENABLE_API_ARMOR
1469ca95730Sdrh   if( pCurrent==0 || pHighwater==0 ) return SQLITE_MISUSE_BKPT;
1479ca95730Sdrh #endif
148af89fe66Sdrh   pMutex = statMutex[op] ? sqlite3Pcache1Mutex() : sqlite3MallocMutex();
149af89fe66Sdrh   sqlite3_mutex_enter(pMutex);
15078f82d1eSdrh   *pCurrent = wsdStat.nowValue[op];
15178f82d1eSdrh   *pHighwater = wsdStat.mxValue[op];
152c4b18b82Sdrh   if( resetFlag ){
15378f82d1eSdrh     wsdStat.mxValue[op] = wsdStat.nowValue[op];
154c4b18b82Sdrh   }
155af89fe66Sdrh   sqlite3_mutex_leave(pMutex);
15647564048Sdrh   (void)pMutex;  /* Prevent warning when SQLITE_THREADSAFE=0 */
157c4b18b82Sdrh   return SQLITE_OK;
158c4b18b82Sdrh }
sqlite3_status(int op,int * pCurrent,int * pHighwater,int resetFlag)159af89fe66Sdrh int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag){
16038b802dfSdrh   sqlite3_int64 iCur = 0, iHwtr = 0;
161af89fe66Sdrh   int rc;
162af89fe66Sdrh #ifdef SQLITE_ENABLE_API_ARMOR
163af89fe66Sdrh   if( pCurrent==0 || pHighwater==0 ) return SQLITE_MISUSE_BKPT;
164af89fe66Sdrh #endif
165af89fe66Sdrh   rc = sqlite3_status64(op, &iCur, &iHwtr, resetFlag);
1662b4905c8Sdrh   if( rc==0 ){
167af89fe66Sdrh     *pCurrent = (int)iCur;
168af89fe66Sdrh     *pHighwater = (int)iHwtr;
1692b4905c8Sdrh   }
170af89fe66Sdrh   return rc;
171af89fe66Sdrh }
172633e6d57Sdrh 
173633e6d57Sdrh /*
17452fb8e19Sdrh ** Return the number of LookasideSlot elements on the linked list
17552fb8e19Sdrh */
countLookasideSlots(LookasideSlot * p)17652fb8e19Sdrh static u32 countLookasideSlots(LookasideSlot *p){
17752fb8e19Sdrh   u32 cnt = 0;
17852fb8e19Sdrh   while( p ){
17952fb8e19Sdrh     p = p->pNext;
18052fb8e19Sdrh     cnt++;
18152fb8e19Sdrh   }
18252fb8e19Sdrh   return cnt;
18352fb8e19Sdrh }
18452fb8e19Sdrh 
18552fb8e19Sdrh /*
18652fb8e19Sdrh ** Count the number of slots of lookaside memory that are outstanding
18752fb8e19Sdrh */
sqlite3LookasideUsed(sqlite3 * db,int * pHighwater)18852fb8e19Sdrh int sqlite3LookasideUsed(sqlite3 *db, int *pHighwater){
18952fb8e19Sdrh   u32 nInit = countLookasideSlots(db->lookaside.pInit);
19052fb8e19Sdrh   u32 nFree = countLookasideSlots(db->lookaside.pFree);
191cf014f6cSdrh #ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE
192cf014f6cSdrh   nInit += countLookasideSlots(db->lookaside.pSmallInit);
193cf014f6cSdrh   nFree += countLookasideSlots(db->lookaside.pSmallFree);
194cf014f6cSdrh #endif /* SQLITE_OMIT_TWOSIZE_LOOKASIDE */
19552fb8e19Sdrh   if( pHighwater ) *pHighwater = db->lookaside.nSlot - nInit;
19652fb8e19Sdrh   return db->lookaside.nSlot - (nInit+nFree);
19752fb8e19Sdrh }
19852fb8e19Sdrh 
19952fb8e19Sdrh /*
200633e6d57Sdrh ** Query status information for a single database connection
201633e6d57Sdrh */
sqlite3_db_status(sqlite3 * db,int op,int * pCurrent,int * pHighwater,int resetFlag)202633e6d57Sdrh int sqlite3_db_status(
203633e6d57Sdrh   sqlite3 *db,          /* The database connection whose status is desired */
204633e6d57Sdrh   int op,               /* Status verb */
205633e6d57Sdrh   int *pCurrent,        /* Write current value here */
206633e6d57Sdrh   int *pHighwater,      /* Write high-water mark here */
207633e6d57Sdrh   int resetFlag         /* Reset high-water mark if true */
208633e6d57Sdrh ){
2092339f067Sdan   int rc = SQLITE_OK;   /* Return code */
2109ca95730Sdrh #ifdef SQLITE_ENABLE_API_ARMOR
2119ca95730Sdrh   if( !sqlite3SafetyCheckOk(db) || pCurrent==0|| pHighwater==0 ){
2129ca95730Sdrh     return SQLITE_MISUSE_BKPT;
2139ca95730Sdrh   }
2149ca95730Sdrh #endif
2152339f067Sdan   sqlite3_mutex_enter(db->mutex);
216633e6d57Sdrh   switch( op ){
217633e6d57Sdrh     case SQLITE_DBSTATUS_LOOKASIDE_USED: {
21852fb8e19Sdrh       *pCurrent = sqlite3LookasideUsed(db, pHighwater);
219633e6d57Sdrh       if( resetFlag ){
22052fb8e19Sdrh         LookasideSlot *p = db->lookaside.pFree;
22152fb8e19Sdrh         if( p ){
22252fb8e19Sdrh           while( p->pNext ) p = p->pNext;
22352fb8e19Sdrh           p->pNext = db->lookaside.pInit;
22452fb8e19Sdrh           db->lookaside.pInit = db->lookaside.pFree;
22552fb8e19Sdrh           db->lookaside.pFree = 0;
22652fb8e19Sdrh         }
227cf014f6cSdrh #ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE
228cf014f6cSdrh         p = db->lookaside.pSmallFree;
229115d663cSnumist         if( p ){
230115d663cSnumist           while( p->pNext ) p = p->pNext;
231cf014f6cSdrh           p->pNext = db->lookaside.pSmallInit;
232cf014f6cSdrh           db->lookaside.pSmallInit = db->lookaside.pSmallFree;
233cf014f6cSdrh           db->lookaside.pSmallFree = 0;
234115d663cSnumist         }
235115d663cSnumist #endif
236633e6d57Sdrh       }
237633e6d57Sdrh       break;
238633e6d57Sdrh     }
23963da0893Sdrh 
2400b12e7f8Sdrh     case SQLITE_DBSTATUS_LOOKASIDE_HIT:
2410b12e7f8Sdrh     case SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE:
2420b12e7f8Sdrh     case SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL: {
2430b12e7f8Sdrh       testcase( op==SQLITE_DBSTATUS_LOOKASIDE_HIT );
2440b12e7f8Sdrh       testcase( op==SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE );
2450b12e7f8Sdrh       testcase( op==SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL );
2460b12e7f8Sdrh       assert( (op-SQLITE_DBSTATUS_LOOKASIDE_HIT)>=0 );
2470b12e7f8Sdrh       assert( (op-SQLITE_DBSTATUS_LOOKASIDE_HIT)<3 );
2480b12e7f8Sdrh       *pCurrent = 0;
2490b12e7f8Sdrh       *pHighwater = db->lookaside.anStat[op - SQLITE_DBSTATUS_LOOKASIDE_HIT];
2500b12e7f8Sdrh       if( resetFlag ){
2510b12e7f8Sdrh         db->lookaside.anStat[op - SQLITE_DBSTATUS_LOOKASIDE_HIT] = 0;
2520b12e7f8Sdrh       }
2530b12e7f8Sdrh       break;
2540b12e7f8Sdrh     }
2550b12e7f8Sdrh 
25663da0893Sdrh     /*
25763da0893Sdrh     ** Return an approximation for the amount of memory currently used
25863da0893Sdrh     ** by all pagers associated with the given database connection.  The
25963da0893Sdrh     ** highwater mark is meaningless and is returned as zero.
26063da0893Sdrh     */
2619c10608aSdan     case SQLITE_DBSTATUS_CACHE_USED_SHARED:
26263da0893Sdrh     case SQLITE_DBSTATUS_CACHE_USED: {
26363da0893Sdrh       int totalUsed = 0;
26463da0893Sdrh       int i;
2652339f067Sdan       sqlite3BtreeEnterAll(db);
26663da0893Sdrh       for(i=0; i<db->nDb; i++){
26763da0893Sdrh         Btree *pBt = db->aDb[i].pBt;
26863da0893Sdrh         if( pBt ){
26963da0893Sdrh           Pager *pPager = sqlite3BtreePager(pBt);
270272989b4Sdan           int nByte = sqlite3PagerMemUsed(pPager);
2719c10608aSdan           if( op==SQLITE_DBSTATUS_CACHE_USED_SHARED ){
272272989b4Sdan             nByte = nByte / sqlite3BtreeConnectionCount(pBt);
273272989b4Sdan           }
274272989b4Sdan           totalUsed += nByte;
27563da0893Sdrh         }
27663da0893Sdrh       }
2772339f067Sdan       sqlite3BtreeLeaveAll(db);
27863da0893Sdrh       *pCurrent = totalUsed;
27963da0893Sdrh       *pHighwater = 0;
28063da0893Sdrh       break;
28163da0893Sdrh     }
282d46def77Sdan 
283643f35e4Sdrh     /*
284643f35e4Sdrh     ** *pCurrent gets an accurate estimate of the amount of memory used
285643f35e4Sdrh     ** to store the schema for all databases (main, temp, and any ATTACHed
286643f35e4Sdrh     ** databases.  *pHighwater is set to zero.
287643f35e4Sdrh     */
288d46def77Sdan     case SQLITE_DBSTATUS_SCHEMA_USED: {
289d46def77Sdan       int i;                      /* Used to iterate through schemas */
290d46def77Sdan       int nByte = 0;              /* Used to accumulate return value */
291d46def77Sdan 
2922120608eSdrh       sqlite3BtreeEnterAll(db);
293d46def77Sdan       db->pnBytesFreed = &nByte;
294376860baSdrh       assert( db->lookaside.pEnd==db->lookaside.pTrueEnd );
295376860baSdrh       db->lookaside.pEnd = db->lookaside.pStart;
296d46def77Sdan       for(i=0; i<db->nDb; i++){
297d46def77Sdan         Schema *pSchema = db->aDb[i].pSchema;
29881ba7d16Sdrh         if( ALWAYS(pSchema!=0) ){
299d46def77Sdan           HashElem *p;
300d46def77Sdan 
301111becfbSdan           nByte += sqlite3GlobalConfig.m.xRoundup(sizeof(HashElem)) * (
302d46def77Sdan               pSchema->tblHash.count
303d46def77Sdan             + pSchema->trigHash.count
304d46def77Sdan             + pSchema->idxHash.count
305d46def77Sdan             + pSchema->fkeyHash.count
306d46def77Sdan           );
307039ca6abSdrh           nByte += sqlite3_msize(pSchema->tblHash.ht);
308039ca6abSdrh           nByte += sqlite3_msize(pSchema->trigHash.ht);
309039ca6abSdrh           nByte += sqlite3_msize(pSchema->idxHash.ht);
310039ca6abSdrh           nByte += sqlite3_msize(pSchema->fkeyHash.ht);
311d46def77Sdan 
312d46def77Sdan           for(p=sqliteHashFirst(&pSchema->trigHash); p; p=sqliteHashNext(p)){
313d46def77Sdan             sqlite3DeleteTrigger(db, (Trigger*)sqliteHashData(p));
314d46def77Sdan           }
315d46def77Sdan           for(p=sqliteHashFirst(&pSchema->tblHash); p; p=sqliteHashNext(p)){
316d46def77Sdan             sqlite3DeleteTable(db, (Table *)sqliteHashData(p));
317d46def77Sdan           }
318d46def77Sdan         }
319d46def77Sdan       }
320d46def77Sdan       db->pnBytesFreed = 0;
321376860baSdrh       db->lookaside.pEnd = db->lookaside.pTrueEnd;
3222120608eSdrh       sqlite3BtreeLeaveAll(db);
323d46def77Sdan 
324d46def77Sdan       *pHighwater = 0;
325d46def77Sdan       *pCurrent = nByte;
326d46def77Sdan       break;
327d46def77Sdan     }
328d46def77Sdan 
329643f35e4Sdrh     /*
330643f35e4Sdrh     ** *pCurrent gets an accurate estimate of the amount of memory used
331643f35e4Sdrh     ** to store all prepared statements.
332643f35e4Sdrh     ** *pHighwater is set to zero.
333643f35e4Sdrh     */
334d46def77Sdan     case SQLITE_DBSTATUS_STMT_USED: {
335d46def77Sdan       struct Vdbe *pVdbe;         /* Used to iterate through VMs */
336d46def77Sdan       int nByte = 0;              /* Used to accumulate return value */
337d46def77Sdan 
338d46def77Sdan       db->pnBytesFreed = &nByte;
339376860baSdrh       assert( db->lookaside.pEnd==db->lookaside.pTrueEnd );
340376860baSdrh       db->lookaside.pEnd = db->lookaside.pStart;
341*e5928b17Sdrh       for(pVdbe=db->pVdbe; pVdbe; pVdbe=pVdbe->pVNext){
3421c848630Sdrh         sqlite3VdbeDelete(pVdbe);
343d46def77Sdan       }
344376860baSdrh       db->lookaside.pEnd = db->lookaside.pTrueEnd;
345d46def77Sdan       db->pnBytesFreed = 0;
346d46def77Sdan 
34779f7af9aSdrh       *pHighwater = 0;  /* IMP: R-64479-57858 */
348d46def77Sdan       *pCurrent = nByte;
349d46def77Sdan 
350d46def77Sdan       break;
351d46def77Sdan     }
352d46def77Sdan 
35358ca31c9Sdan     /*
35458ca31c9Sdan     ** Set *pCurrent to the total cache hits or misses encountered by all
35558ca31c9Sdan     ** pagers the database handle is connected to. *pHighwater is always set
35658ca31c9Sdan     ** to zero.
35758ca31c9Sdan     */
358ffc78a41Sdrh     case SQLITE_DBSTATUS_CACHE_SPILL:
359ffc78a41Sdrh       op = SQLITE_DBSTATUS_CACHE_WRITE+1;
36008b92086Sdrh       /* no break */ deliberate_fall_through
36158ca31c9Sdan     case SQLITE_DBSTATUS_CACHE_HIT:
3629ad3ee40Sdrh     case SQLITE_DBSTATUS_CACHE_MISS:
3639ad3ee40Sdrh     case SQLITE_DBSTATUS_CACHE_WRITE:{
36458ca31c9Sdan       int i;
36558ca31c9Sdan       int nRet = 0;
36658ca31c9Sdan       assert( SQLITE_DBSTATUS_CACHE_MISS==SQLITE_DBSTATUS_CACHE_HIT+1 );
3679ad3ee40Sdrh       assert( SQLITE_DBSTATUS_CACHE_WRITE==SQLITE_DBSTATUS_CACHE_HIT+2 );
36858ca31c9Sdan 
36958ca31c9Sdan       for(i=0; i<db->nDb; i++){
37058ca31c9Sdan         if( db->aDb[i].pBt ){
37158ca31c9Sdan           Pager *pPager = sqlite3BtreePager(db->aDb[i].pBt);
37258ca31c9Sdan           sqlite3PagerCacheStat(pPager, op, resetFlag, &nRet);
37358ca31c9Sdan         }
37458ca31c9Sdan       }
37579f7af9aSdrh       *pHighwater = 0; /* IMP: R-42420-56072 */
37679f7af9aSdrh                        /* IMP: R-54100-20147 */
37779f7af9aSdrh                        /* IMP: R-29431-39229 */
37858ca31c9Sdan       *pCurrent = nRet;
37958ca31c9Sdan       break;
38058ca31c9Sdan     }
38158ca31c9Sdan 
382648e2643Sdrh     /* Set *pCurrent to non-zero if there are unresolved deferred foreign
383648e2643Sdrh     ** key constraints.  Set *pCurrent to zero if all foreign key constraints
384648e2643Sdrh     ** have been satisfied.  The *pHighwater is always set to zero.
385648e2643Sdrh     */
386648e2643Sdrh     case SQLITE_DBSTATUS_DEFERRED_FKS: {
38779f7af9aSdrh       *pHighwater = 0;  /* IMP: R-11967-56545 */
388648e2643Sdrh       *pCurrent = db->nDeferredImmCons>0 || db->nDeferredCons>0;
389648e2643Sdrh       break;
390648e2643Sdrh     }
391648e2643Sdrh 
3926480aad4Sdrh     default: {
3932339f067Sdan       rc = SQLITE_ERROR;
3946480aad4Sdrh     }
395633e6d57Sdrh   }
3962339f067Sdan   sqlite3_mutex_leave(db->mutex);
3972339f067Sdan   return rc;
398633e6d57Sdrh }
399