| OLD | NEW |
| 1 /* | 1 /* |
| 2 ** 2010 July 12 | 2 ** 2010 July 12 |
| 3 ** | 3 ** |
| 4 ** The author disclaims copyright to this source code. In place of | 4 ** The author disclaims copyright to this source code. In place of |
| 5 ** a legal notice, here is a blessing: | 5 ** a legal notice, here is a blessing: |
| 6 ** | 6 ** |
| 7 ** May you do good and not evil. | 7 ** May you do good and not evil. |
| 8 ** May you find forgiveness for yourself and forgive others. | 8 ** May you find forgiveness for yourself and forgive others. |
| 9 ** May you share freely, never taking more than you give. | 9 ** May you share freely, never taking more than you give. |
| 10 ** | 10 ** |
| 11 ****************************************************************************** | 11 ****************************************************************************** |
| 12 ** | 12 ** |
| 13 ** This file contains an implementation of the "dbstat" virtual table. | 13 ** This file contains an implementation of the "dbstat" virtual table. |
| 14 ** | 14 ** |
| 15 ** The dbstat virtual table is used to extract low-level formatting | 15 ** The dbstat virtual table is used to extract low-level formatting |
| 16 ** information from an SQLite database in order to implement the | 16 ** information from an SQLite database in order to implement the |
| 17 ** "sqlite3_analyzer" utility. See the ../tool/spaceanal.tcl script | 17 ** "sqlite3_analyzer" utility. See the ../tool/spaceanal.tcl script |
| 18 ** for an example implementation. | 18 ** for an example implementation. |
| 19 */ | 19 */ |
| 20 | 20 |
| 21 #include "sqliteInt.h" | 21 #ifndef SQLITE_AMALGAMATION |
| 22 # include "sqliteInt.h" |
| 23 #endif |
| 22 | 24 |
| 23 #ifndef SQLITE_OMIT_VIRTUALTABLE | 25 #ifndef SQLITE_OMIT_VIRTUALTABLE |
| 24 | 26 |
| 25 /* | 27 /* |
| 26 ** Page paths: | 28 ** Page paths: |
| 27 ** | 29 ** |
| 28 ** The value of the 'path' column describes the path taken from the | 30 ** The value of the 'path' column describes the path taken from the |
| 29 ** root-node of the b-tree structure to each page. The value of the | 31 ** root-node of the b-tree structure to each page. The value of the |
| 30 ** root-node path is '/'. | 32 ** root-node path is '/'. |
| 31 ** | 33 ** |
| (...skipping 23 matching lines...) Expand all Loading... |
| 55 */ | 57 */ |
| 56 #define VTAB_SCHEMA \ | 58 #define VTAB_SCHEMA \ |
| 57 "CREATE TABLE xx( " \ | 59 "CREATE TABLE xx( " \ |
| 58 " name STRING, /* Name of table or index */" \ | 60 " name STRING, /* Name of table or index */" \ |
| 59 " path INTEGER, /* Path to page from root */" \ | 61 " path INTEGER, /* Path to page from root */" \ |
| 60 " pageno INTEGER, /* Page number */" \ | 62 " pageno INTEGER, /* Page number */" \ |
| 61 " pagetype STRING, /* 'internal', 'leaf' or 'overflow' */" \ | 63 " pagetype STRING, /* 'internal', 'leaf' or 'overflow' */" \ |
| 62 " ncell INTEGER, /* Cells on page (0 for overflow) */" \ | 64 " ncell INTEGER, /* Cells on page (0 for overflow) */" \ |
| 63 " payload INTEGER, /* Bytes of payload on this page */" \ | 65 " payload INTEGER, /* Bytes of payload on this page */" \ |
| 64 " unused INTEGER, /* Bytes of unused space on this page */" \ | 66 " unused INTEGER, /* Bytes of unused space on this page */" \ |
| 65 " mx_payload INTEGER /* Largest payload size of all cells */" \ | 67 " mx_payload INTEGER, /* Largest payload size of all cells */" \ |
| 68 " pgoffset INTEGER, /* Offset of page in file */" \ |
| 69 " pgsize INTEGER /* Size of the page */" \ |
| 66 ");" | 70 ");" |
| 67 | 71 |
| 68 #if 0 | |
| 69 #define VTAB_SCHEMA2 \ | |
| 70 "CREATE TABLE yy( " \ | |
| 71 " pageno INTEGER, /* B-tree page number */" \ | |
| 72 " cellno INTEGER, /* Cell number within page */" \ | |
| 73 " local INTEGER, /* Bytes of content stored locally */" \ | |
| 74 " payload INTEGER, /* Total cell payload size */" \ | |
| 75 " novfl INTEGER /* Number of overflow pages */" \ | |
| 76 ");" | |
| 77 #endif | |
| 78 | |
| 79 | 72 |
| 80 typedef struct StatTable StatTable; | 73 typedef struct StatTable StatTable; |
| 81 typedef struct StatCursor StatCursor; | 74 typedef struct StatCursor StatCursor; |
| 82 typedef struct StatPage StatPage; | 75 typedef struct StatPage StatPage; |
| 83 typedef struct StatCell StatCell; | 76 typedef struct StatCell StatCell; |
| 84 | 77 |
| 85 struct StatCell { | 78 struct StatCell { |
| 86 int nLocal; /* Bytes of local payload */ | 79 int nLocal; /* Bytes of local payload */ |
| 87 u32 iChildPg; /* Child node (or 0 if this is a leaf) */ | 80 u32 iChildPg; /* Child node (or 0 if this is a leaf) */ |
| 88 int nOvfl; /* Entries in aOvfl[] */ | 81 int nOvfl; /* Entries in aOvfl[] */ |
| (...skipping 28 matching lines...) Expand all Loading... |
| 117 | 110 |
| 118 /* Values to return. */ | 111 /* Values to return. */ |
| 119 char *zName; /* Value of 'name' column */ | 112 char *zName; /* Value of 'name' column */ |
| 120 char *zPath; /* Value of 'path' column */ | 113 char *zPath; /* Value of 'path' column */ |
| 121 u32 iPageno; /* Value of 'pageno' column */ | 114 u32 iPageno; /* Value of 'pageno' column */ |
| 122 char *zPagetype; /* Value of 'pagetype' column */ | 115 char *zPagetype; /* Value of 'pagetype' column */ |
| 123 int nCell; /* Value of 'ncell' column */ | 116 int nCell; /* Value of 'ncell' column */ |
| 124 int nPayload; /* Value of 'payload' column */ | 117 int nPayload; /* Value of 'payload' column */ |
| 125 int nUnused; /* Value of 'unused' column */ | 118 int nUnused; /* Value of 'unused' column */ |
| 126 int nMxPayload; /* Value of 'mx_payload' column */ | 119 int nMxPayload; /* Value of 'mx_payload' column */ |
| 120 i64 iOffset; /* Value of 'pgOffset' column */ |
| 121 int szPage; /* Value of 'pgSize' column */ |
| 127 }; | 122 }; |
| 128 | 123 |
| 129 struct StatTable { | 124 struct StatTable { |
| 130 sqlite3_vtab base; | 125 sqlite3_vtab base; |
| 131 sqlite3 *db; | 126 sqlite3 *db; |
| 132 }; | 127 }; |
| 133 | 128 |
| 134 #ifndef get2byte | 129 #ifndef get2byte |
| 135 # define get2byte(x) ((x)[0]<<8 | (x)[1]) | 130 # define get2byte(x) ((x)[0]<<8 | (x)[1]) |
| 136 #endif | 131 #endif |
| (...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 274 nLocal = nMinLocal + (nTotal - nMinLocal) % (nUsable - 4); | 269 nLocal = nMinLocal + (nTotal - nMinLocal) % (nUsable - 4); |
| 275 if( nLocal>nMaxLocal ) nLocal = nMinLocal; | 270 if( nLocal>nMaxLocal ) nLocal = nMinLocal; |
| 276 *pnLocal = nLocal; | 271 *pnLocal = nLocal; |
| 277 } | 272 } |
| 278 | 273 |
| 279 static int statDecodePage(Btree *pBt, StatPage *p){ | 274 static int statDecodePage(Btree *pBt, StatPage *p){ |
| 280 int nUnused; | 275 int nUnused; |
| 281 int iOff; | 276 int iOff; |
| 282 int nHdr; | 277 int nHdr; |
| 283 int isLeaf; | 278 int isLeaf; |
| 279 int szPage; |
| 284 | 280 |
| 285 u8 *aData = sqlite3PagerGetData(p->pPg); | 281 u8 *aData = sqlite3PagerGetData(p->pPg); |
| 286 u8 *aHdr = &aData[p->iPgno==1 ? 100 : 0]; | 282 u8 *aHdr = &aData[p->iPgno==1 ? 100 : 0]; |
| 287 | 283 |
| 288 p->flags = aHdr[0]; | 284 p->flags = aHdr[0]; |
| 289 p->nCell = get2byte(&aHdr[3]); | 285 p->nCell = get2byte(&aHdr[3]); |
| 290 p->nMxPayload = 0; | 286 p->nMxPayload = 0; |
| 291 | 287 |
| 292 isLeaf = (p->flags==0x0A || p->flags==0x0D); | 288 isLeaf = (p->flags==0x0A || p->flags==0x0D); |
| 293 nHdr = 12 - isLeaf*4 + (p->iPgno==1)*100; | 289 nHdr = 12 - isLeaf*4 + (p->iPgno==1)*100; |
| 294 | 290 |
| 295 nUnused = get2byte(&aHdr[5]) - nHdr - 2*p->nCell; | 291 nUnused = get2byte(&aHdr[5]) - nHdr - 2*p->nCell; |
| 296 nUnused += (int)aHdr[7]; | 292 nUnused += (int)aHdr[7]; |
| 297 iOff = get2byte(&aHdr[1]); | 293 iOff = get2byte(&aHdr[1]); |
| 298 while( iOff ){ | 294 while( iOff ){ |
| 299 nUnused += get2byte(&aData[iOff+2]); | 295 nUnused += get2byte(&aData[iOff+2]); |
| 300 iOff = get2byte(&aData[iOff]); | 296 iOff = get2byte(&aData[iOff]); |
| 301 } | 297 } |
| 302 p->nUnused = nUnused; | 298 p->nUnused = nUnused; |
| 303 p->iRightChildPg = isLeaf ? 0 : sqlite3Get4byte(&aHdr[8]); | 299 p->iRightChildPg = isLeaf ? 0 : sqlite3Get4byte(&aHdr[8]); |
| 300 szPage = sqlite3BtreeGetPageSize(pBt); |
| 304 | 301 |
| 305 if( p->nCell ){ | 302 if( p->nCell ){ |
| 306 int i; /* Used to iterate through cells */ | 303 int i; /* Used to iterate through cells */ |
| 307 int nUsable = sqlite3BtreeGetPageSize(pBt) - sqlite3BtreeGetReserve(pBt); | 304 int nUsable = szPage - sqlite3BtreeGetReserve(pBt); |
| 308 | 305 |
| 309 p->aCell = sqlite3_malloc((p->nCell+1) * sizeof(StatCell)); | 306 p->aCell = sqlite3_malloc((p->nCell+1) * sizeof(StatCell)); |
| 310 memset(p->aCell, 0, (p->nCell+1) * sizeof(StatCell)); | 307 memset(p->aCell, 0, (p->nCell+1) * sizeof(StatCell)); |
| 311 | 308 |
| 312 for(i=0; i<p->nCell; i++){ | 309 for(i=0; i<p->nCell; i++){ |
| 313 StatCell *pCell = &p->aCell[i]; | 310 StatCell *pCell = &p->aCell[i]; |
| 314 | 311 |
| 315 iOff = get2byte(&aData[nHdr+i*2]); | 312 iOff = get2byte(&aData[nHdr+i*2]); |
| 316 if( !isLeaf ){ | 313 if( !isLeaf ){ |
| 317 pCell->iChildPg = sqlite3Get4byte(&aData[iOff]); | 314 pCell->iChildPg = sqlite3Get4byte(&aData[iOff]); |
| 318 iOff += 4; | 315 iOff += 4; |
| 319 } | 316 } |
| 320 if( p->flags==0x05 ){ | 317 if( p->flags==0x05 ){ |
| 321 /* A table interior node. nPayload==0. */ | 318 /* A table interior node. nPayload==0. */ |
| 322 }else{ | 319 }else{ |
| 323 u32 nPayload; /* Bytes of payload total (local+overflow) */ | 320 u32 nPayload; /* Bytes of payload total (local+overflow) */ |
| 324 int nLocal; /* Bytes of payload stored locally */ | 321 int nLocal; /* Bytes of payload stored locally */ |
| 325 iOff += getVarint32(&aData[iOff], nPayload); | 322 iOff += getVarint32(&aData[iOff], nPayload); |
| 326 if( p->flags==0x0D ){ | 323 if( p->flags==0x0D ){ |
| 327 u64 dummy; | 324 u64 dummy; |
| 328 iOff += sqlite3GetVarint(&aData[iOff], &dummy); | 325 iOff += sqlite3GetVarint(&aData[iOff], &dummy); |
| 329 } | 326 } |
| 330 if( nPayload>p->nMxPayload ) p->nMxPayload = nPayload; | 327 if( nPayload>(u32)p->nMxPayload ) p->nMxPayload = nPayload; |
| 331 getLocalPayload(nUsable, p->flags, nPayload, &nLocal); | 328 getLocalPayload(nUsable, p->flags, nPayload, &nLocal); |
| 332 pCell->nLocal = nLocal; | 329 pCell->nLocal = nLocal; |
| 333 assert( nPayload>=nLocal ); | 330 assert( nLocal>=0 ); |
| 331 assert( nPayload>=(u32)nLocal ); |
| 334 assert( nLocal<=(nUsable-35) ); | 332 assert( nLocal<=(nUsable-35) ); |
| 335 if( nPayload>nLocal ){ | 333 if( nPayload>(u32)nLocal ){ |
| 336 int j; | 334 int j; |
| 337 int nOvfl = ((nPayload - nLocal) + nUsable-4 - 1) / (nUsable - 4); | 335 int nOvfl = ((nPayload - nLocal) + nUsable-4 - 1) / (nUsable - 4); |
| 338 pCell->nLastOvfl = (nPayload-nLocal) - (nOvfl-1) * (nUsable-4); | 336 pCell->nLastOvfl = (nPayload-nLocal) - (nOvfl-1) * (nUsable-4); |
| 339 pCell->nOvfl = nOvfl; | 337 pCell->nOvfl = nOvfl; |
| 340 pCell->aOvfl = sqlite3_malloc(sizeof(u32)*nOvfl); | 338 pCell->aOvfl = sqlite3_malloc(sizeof(u32)*nOvfl); |
| 341 pCell->aOvfl[0] = sqlite3Get4byte(&aData[iOff+nLocal]); | 339 pCell->aOvfl[0] = sqlite3Get4byte(&aData[iOff+nLocal]); |
| 342 for(j=1; j<nOvfl; j++){ | 340 for(j=1; j<nOvfl; j++){ |
| 343 int rc; | 341 int rc; |
| 344 u32 iPrev = pCell->aOvfl[j-1]; | 342 u32 iPrev = pCell->aOvfl[j-1]; |
| 345 DbPage *pPg = 0; | 343 DbPage *pPg = 0; |
| 346 rc = sqlite3PagerGet(sqlite3BtreePager(pBt), iPrev, &pPg); | 344 rc = sqlite3PagerGet(sqlite3BtreePager(pBt), iPrev, &pPg); |
| 347 if( rc!=SQLITE_OK ){ | 345 if( rc!=SQLITE_OK ){ |
| 348 assert( pPg==0 ); | 346 assert( pPg==0 ); |
| 349 return rc; | 347 return rc; |
| 350 } | 348 } |
| 351 pCell->aOvfl[j] = sqlite3Get4byte(sqlite3PagerGetData(pPg)); | 349 pCell->aOvfl[j] = sqlite3Get4byte(sqlite3PagerGetData(pPg)); |
| 352 sqlite3PagerUnref(pPg); | 350 sqlite3PagerUnref(pPg); |
| 353 } | 351 } |
| 354 } | 352 } |
| 355 } | 353 } |
| 356 } | 354 } |
| 357 } | 355 } |
| 358 | 356 |
| 359 return SQLITE_OK; | 357 return SQLITE_OK; |
| 360 } | 358 } |
| 361 | 359 |
| 362 /* | 360 /* |
| 361 ** Populate the pCsr->iOffset and pCsr->szPage member variables. Based on |
| 362 ** the current value of pCsr->iPageno. |
| 363 */ |
| 364 static void statSizeAndOffset(StatCursor *pCsr){ |
| 365 StatTable *pTab = (StatTable *)((sqlite3_vtab_cursor *)pCsr)->pVtab; |
| 366 Btree *pBt = pTab->db->aDb[0].pBt; |
| 367 Pager *pPager = sqlite3BtreePager(pBt); |
| 368 sqlite3_file *fd; |
| 369 sqlite3_int64 x[2]; |
| 370 |
| 371 /* The default page size and offset */ |
| 372 pCsr->szPage = sqlite3BtreeGetPageSize(pBt); |
| 373 pCsr->iOffset = (i64)pCsr->szPage * (pCsr->iPageno - 1); |
| 374 |
| 375 /* If connected to a ZIPVFS backend, override the page size and |
| 376 ** offset with actual values obtained from ZIPVFS. |
| 377 */ |
| 378 fd = sqlite3PagerFile(pPager); |
| 379 x[0] = pCsr->iPageno; |
| 380 if( sqlite3OsFileControl(fd, 230440, &x)==SQLITE_OK ){ |
| 381 pCsr->iOffset = x[0]; |
| 382 pCsr->szPage = (int)x[1]; |
| 383 } |
| 384 } |
| 385 |
| 386 /* |
| 363 ** Move a statvfs cursor to the next entry in the file. | 387 ** Move a statvfs cursor to the next entry in the file. |
| 364 */ | 388 */ |
| 365 static int statNext(sqlite3_vtab_cursor *pCursor){ | 389 static int statNext(sqlite3_vtab_cursor *pCursor){ |
| 366 int rc; | 390 int rc; |
| 367 int nPayload; | 391 int nPayload; |
| 368 StatCursor *pCsr = (StatCursor *)pCursor; | 392 StatCursor *pCsr = (StatCursor *)pCursor; |
| 369 StatTable *pTab = (StatTable *)pCursor->pVtab; | 393 StatTable *pTab = (StatTable *)pCursor->pVtab; |
| 370 Btree *pBt = pTab->db->aDb[0].pBt; | 394 Btree *pBt = pTab->db->aDb[0].pBt; |
| 371 Pager *pPager = sqlite3BtreePager(pBt); | 395 Pager *pPager = sqlite3BtreePager(pBt); |
| 372 | 396 |
| 373 sqlite3_free(pCsr->zPath); | 397 sqlite3_free(pCsr->zPath); |
| 374 pCsr->zPath = 0; | 398 pCsr->zPath = 0; |
| 375 | 399 |
| 400 statNextRestart: |
| 376 if( pCsr->aPage[0].pPg==0 ){ | 401 if( pCsr->aPage[0].pPg==0 ){ |
| 377 rc = sqlite3_step(pCsr->pStmt); | 402 rc = sqlite3_step(pCsr->pStmt); |
| 378 if( rc==SQLITE_ROW ){ | 403 if( rc==SQLITE_ROW ){ |
| 379 int nPage; | 404 int nPage; |
| 380 u32 iRoot = sqlite3_column_int64(pCsr->pStmt, 1); | 405 u32 iRoot = (u32)sqlite3_column_int64(pCsr->pStmt, 1); |
| 381 sqlite3PagerPagecount(pPager, &nPage); | 406 sqlite3PagerPagecount(pPager, &nPage); |
| 382 if( nPage==0 ){ | 407 if( nPage==0 ){ |
| 383 pCsr->isEof = 1; | 408 pCsr->isEof = 1; |
| 384 return sqlite3_reset(pCsr->pStmt); | 409 return sqlite3_reset(pCsr->pStmt); |
| 385 } | 410 } |
| 386 rc = sqlite3PagerGet(pPager, iRoot, &pCsr->aPage[0].pPg); | 411 rc = sqlite3PagerGet(pPager, iRoot, &pCsr->aPage[0].pPg); |
| 387 pCsr->aPage[0].iPgno = iRoot; | 412 pCsr->aPage[0].iPgno = iRoot; |
| 388 pCsr->aPage[0].iCell = 0; | 413 pCsr->aPage[0].iCell = 0; |
| 389 pCsr->aPage[0].zPath = sqlite3_mprintf("/"); | 414 pCsr->aPage[0].zPath = sqlite3_mprintf("/"); |
| 390 pCsr->iPage = 0; | 415 pCsr->iPage = 0; |
| (...skipping 19 matching lines...) Expand all Loading... |
| 410 "%s%.3x+%.6x", p->zPath, p->iCell, pCell->iOvfl | 435 "%s%.3x+%.6x", p->zPath, p->iCell, pCell->iOvfl |
| 411 ); | 436 ); |
| 412 if( pCell->iOvfl<pCell->nOvfl-1 ){ | 437 if( pCell->iOvfl<pCell->nOvfl-1 ){ |
| 413 pCsr->nUnused = 0; | 438 pCsr->nUnused = 0; |
| 414 pCsr->nPayload = nUsable - 4; | 439 pCsr->nPayload = nUsable - 4; |
| 415 }else{ | 440 }else{ |
| 416 pCsr->nPayload = pCell->nLastOvfl; | 441 pCsr->nPayload = pCell->nLastOvfl; |
| 417 pCsr->nUnused = nUsable - 4 - pCsr->nPayload; | 442 pCsr->nUnused = nUsable - 4 - pCsr->nPayload; |
| 418 } | 443 } |
| 419 pCell->iOvfl++; | 444 pCell->iOvfl++; |
| 445 statSizeAndOffset(pCsr); |
| 420 return SQLITE_OK; | 446 return SQLITE_OK; |
| 421 } | 447 } |
| 422 if( p->iRightChildPg ) break; | 448 if( p->iRightChildPg ) break; |
| 423 p->iCell++; | 449 p->iCell++; |
| 424 } | 450 } |
| 425 | 451 |
| 426 while( !p->iRightChildPg || p->iCell>p->nCell ){ | 452 if( !p->iRightChildPg || p->iCell>p->nCell ){ |
| 427 statClearPage(p); | 453 statClearPage(p); |
| 428 if( pCsr->iPage==0 ) return statNext(pCursor); | 454 if( pCsr->iPage==0 ) return statNext(pCursor); |
| 429 pCsr->iPage--; | 455 pCsr->iPage--; |
| 430 p = &pCsr->aPage[pCsr->iPage]; | 456 goto statNextRestart; /* Tail recursion */ |
| 431 } | 457 } |
| 432 pCsr->iPage++; | 458 pCsr->iPage++; |
| 433 assert( p==&pCsr->aPage[pCsr->iPage-1] ); | 459 assert( p==&pCsr->aPage[pCsr->iPage-1] ); |
| 434 | 460 |
| 435 if( p->iCell==p->nCell ){ | 461 if( p->iCell==p->nCell ){ |
| 436 p[1].iPgno = p->iRightChildPg; | 462 p[1].iPgno = p->iRightChildPg; |
| 437 }else{ | 463 }else{ |
| 438 p[1].iPgno = p->aCell[p->iCell].iChildPg; | 464 p[1].iPgno = p->aCell[p->iCell].iChildPg; |
| 439 } | 465 } |
| 440 rc = sqlite3PagerGet(pPager, p[1].iPgno, &p[1].pPg); | 466 rc = sqlite3PagerGet(pPager, p[1].iPgno, &p[1].pPg); |
| 441 p[1].iCell = 0; | 467 p[1].iCell = 0; |
| 442 p[1].zPath = sqlite3_mprintf("%s%.3x/", p->zPath, p->iCell); | 468 p[1].zPath = sqlite3_mprintf("%s%.3x/", p->zPath, p->iCell); |
| 443 p->iCell++; | 469 p->iCell++; |
| 444 } | 470 } |
| 445 | 471 |
| 446 | 472 |
| 447 /* Populate the StatCursor fields with the values to be returned | 473 /* Populate the StatCursor fields with the values to be returned |
| 448 ** by the xColumn() and xRowid() methods. | 474 ** by the xColumn() and xRowid() methods. |
| 449 */ | 475 */ |
| 450 if( rc==SQLITE_OK ){ | 476 if( rc==SQLITE_OK ){ |
| 451 int i; | 477 int i; |
| 452 StatPage *p = &pCsr->aPage[pCsr->iPage]; | 478 StatPage *p = &pCsr->aPage[pCsr->iPage]; |
| 453 pCsr->zName = (char *)sqlite3_column_text(pCsr->pStmt, 0); | 479 pCsr->zName = (char *)sqlite3_column_text(pCsr->pStmt, 0); |
| 454 pCsr->iPageno = p->iPgno; | 480 pCsr->iPageno = p->iPgno; |
| 455 | 481 |
| 456 statDecodePage(pBt, p); | 482 statDecodePage(pBt, p); |
| 483 statSizeAndOffset(pCsr); |
| 457 | 484 |
| 458 switch( p->flags ){ | 485 switch( p->flags ){ |
| 459 case 0x05: /* table internal */ | 486 case 0x05: /* table internal */ |
| 460 case 0x02: /* index internal */ | 487 case 0x02: /* index internal */ |
| 461 pCsr->zPagetype = "internal"; | 488 pCsr->zPagetype = "internal"; |
| 462 break; | 489 break; |
| 463 case 0x0D: /* table leaf */ | 490 case 0x0D: /* table leaf */ |
| 464 case 0x0A: /* index leaf */ | 491 case 0x0A: /* index leaf */ |
| 465 pCsr->zPagetype = "leaf"; | 492 pCsr->zPagetype = "leaf"; |
| 466 break; | 493 break; |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 522 break; | 549 break; |
| 523 case 5: /* payload */ | 550 case 5: /* payload */ |
| 524 sqlite3_result_int(ctx, pCsr->nPayload); | 551 sqlite3_result_int(ctx, pCsr->nPayload); |
| 525 break; | 552 break; |
| 526 case 6: /* unused */ | 553 case 6: /* unused */ |
| 527 sqlite3_result_int(ctx, pCsr->nUnused); | 554 sqlite3_result_int(ctx, pCsr->nUnused); |
| 528 break; | 555 break; |
| 529 case 7: /* mx_payload */ | 556 case 7: /* mx_payload */ |
| 530 sqlite3_result_int(ctx, pCsr->nMxPayload); | 557 sqlite3_result_int(ctx, pCsr->nMxPayload); |
| 531 break; | 558 break; |
| 559 case 8: /* pgoffset */ |
| 560 sqlite3_result_int64(ctx, pCsr->iOffset); |
| 561 break; |
| 562 case 9: /* pgsize */ |
| 563 sqlite3_result_int(ctx, pCsr->szPage); |
| 564 break; |
| 532 } | 565 } |
| 533 return SQLITE_OK; | 566 return SQLITE_OK; |
| 534 } | 567 } |
| 535 | 568 |
| 536 static int statRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){ | 569 static int statRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){ |
| 537 StatCursor *pCsr = (StatCursor *)pCursor; | 570 StatCursor *pCsr = (StatCursor *)pCursor; |
| 538 *pRowid = pCsr->iPageno; | 571 *pRowid = pCsr->iPageno; |
| 539 return SQLITE_OK; | 572 return SQLITE_OK; |
| 540 } | 573 } |
| 541 | 574 |
| (...skipping 19 matching lines...) Expand all Loading... |
| 561 0, /* xRollback */ | 594 0, /* xRollback */ |
| 562 0, /* xFindMethod */ | 595 0, /* xFindMethod */ |
| 563 0, /* xRename */ | 596 0, /* xRename */ |
| 564 }; | 597 }; |
| 565 sqlite3_create_module(db, "dbstat", &dbstat_module, 0); | 598 sqlite3_create_module(db, "dbstat", &dbstat_module, 0); |
| 566 return SQLITE_OK; | 599 return SQLITE_OK; |
| 567 } | 600 } |
| 568 | 601 |
| 569 #endif | 602 #endif |
| 570 | 603 |
| 571 #ifdef SQLITE_TEST | 604 #if defined(SQLITE_TEST) || TCLSH==2 |
| 572 #include <tcl.h> | 605 #include <tcl.h> |
| 573 | 606 |
| 574 static int test_dbstat( | 607 static int test_dbstat( |
| 575 void *clientData, | 608 void *clientData, |
| 576 Tcl_Interp *interp, | 609 Tcl_Interp *interp, |
| 577 int objc, | 610 int objc, |
| 578 Tcl_Obj *CONST objv[] | 611 Tcl_Obj *CONST objv[] |
| 579 ){ | 612 ){ |
| 580 #ifdef SQLITE_OMIT_VIRTUALTABLE | 613 #ifdef SQLITE_OMIT_VIRTUALTABLE |
| 581 Tcl_AppendResult(interp, "dbstat not available because of " | 614 Tcl_AppendResult(interp, "dbstat not available because of " |
| (...skipping 15 matching lines...) Expand all Loading... |
| 597 sqlite3_dbstat_register(db); | 630 sqlite3_dbstat_register(db); |
| 598 } | 631 } |
| 599 return TCL_OK; | 632 return TCL_OK; |
| 600 #endif | 633 #endif |
| 601 } | 634 } |
| 602 | 635 |
| 603 int SqlitetestStat_Init(Tcl_Interp *interp){ | 636 int SqlitetestStat_Init(Tcl_Interp *interp){ |
| 604 Tcl_CreateObjCommand(interp, "register_dbstat_vtab", test_dbstat, 0, 0); | 637 Tcl_CreateObjCommand(interp, "register_dbstat_vtab", test_dbstat, 0, 0); |
| 605 return TCL_OK; | 638 return TCL_OK; |
| 606 } | 639 } |
| 607 #endif | 640 #endif /* if defined(SQLITE_TEST) || TCLSH==2 */ |
| OLD | NEW |