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