summaryrefslogtreecommitdiff
path: root/tool/showdb.c
diff options
context:
space:
mode:
Diffstat (limited to 'tool/showdb.c')
-rw-r--r--tool/showdb.c111
1 files changed, 97 insertions, 14 deletions
diff --git a/tool/showdb.c b/tool/showdb.c
index d378d05..27424e0 100644
--- a/tool/showdb.c
+++ b/tool/showdb.c
@@ -6,7 +6,11 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
+
+#if !defined(_MSC_VER)
#include <unistd.h>
+#endif
+
#include <stdlib.h>
#include <string.h>
#include "sqlite3.h"
@@ -172,7 +176,7 @@ static void print_db_header(void){
print_decode_line(aData, 56, 4, "Text encoding");
print_decode_line(aData, 60, 4, "User version");
print_decode_line(aData, 64, 4, "Incremental-vacuum mode");
- print_decode_line(aData, 68, 4, "meta[7]");
+ print_decode_line(aData, 68, 4, "Application ID");
print_decode_line(aData, 72, 4, "meta[8]");
print_decode_line(aData, 76, 4, "meta[9]");
print_decode_line(aData, 80, 4, "meta[10]");
@@ -467,7 +471,7 @@ static void page_usage_msg(int pgno, const char *zFormat, ...){
zMsg = sqlite3_vmprintf(zFormat, ap);
va_end(ap);
if( pgno<=0 || pgno>mxPage ){
- printf("ERROR: page %d out of bounds. Range=1..%d. Msg: %s\n",
+ printf("ERROR: page %d out of range 1..%d: %s\n",
pgno, mxPage, zMsg);
sqlite3_free(zMsg);
return;
@@ -475,7 +479,7 @@ static void page_usage_msg(int pgno, const char *zFormat, ...){
if( zPageUse[pgno]!=0 ){
printf("ERROR: page %d used multiple times:\n", pgno);
printf("ERROR: previous: %s\n", zPageUse[pgno]);
- printf("ERROR: current: %s\n", zPageUse[pgno]);
+ printf("ERROR: current: %s\n", zMsg);
sqlite3_free(zPageUse[pgno]);
}
zPageUse[pgno] = zMsg;
@@ -612,14 +616,31 @@ static void page_usage_freelist(int pgno){
}
/*
+** Determine pages used as PTRMAP pages
+*/
+static void page_usage_ptrmap(unsigned char *a){
+ if( a[55] ){
+ int usable = pagesize - a[20];
+ int pgno = 2;
+ int perPage = usable/5;
+ while( pgno<=mxPage ){
+ page_usage_msg(pgno, "PTRMAP page covering %d..%d",
+ pgno+1, pgno+perPage);
+ pgno += perPage + 1;
+ }
+ }
+}
+
+/*
** Try to figure out how every page in the database file is being used.
*/
static void page_usage_report(const char *zDbName){
- int i;
+ int i, j;
int rc;
sqlite3 *db;
sqlite3_stmt *pStmt;
unsigned char *a;
+ char zQuery[200];
/* Avoid the pathological case */
if( mxPage<1 ){
@@ -644,20 +665,26 @@ static void page_usage_report(const char *zDbName){
/* Discover the usage of each page */
a = getContent(0, 100);
page_usage_freelist(decodeInt32(a+32));
+ page_usage_ptrmap(a);
free(a);
page_usage_btree(1, 0, 0, "sqlite_master");
- rc = sqlite3_prepare_v2(db,
- "SELECT type, name, rootpage FROM SQLITE_MASTER WHERE rootpage",
- -1, &pStmt, 0);
- if( rc==SQLITE_OK ){
- while( sqlite3_step(pStmt)==SQLITE_ROW ){
- int pgno = sqlite3_column_int(pStmt, 2);
- page_usage_btree(pgno, 0, 0, sqlite3_column_text(pStmt, 1));
+ sqlite3_exec(db, "PRAGMA writable_schema=ON", 0, 0, 0);
+ for(j=0; j<2; j++){
+ sqlite3_snprintf(sizeof(zQuery), zQuery,
+ "SELECT type, name, rootpage FROM SQLITE_MASTER WHERE rootpage"
+ " ORDER BY rowid %s", j?"DESC":"");
+ rc = sqlite3_prepare_v2(db, zQuery, -1, &pStmt, 0);
+ if( rc==SQLITE_OK ){
+ while( sqlite3_step(pStmt)==SQLITE_ROW ){
+ int pgno = sqlite3_column_int(pStmt, 2);
+ page_usage_btree(pgno, 0, 0, sqlite3_column_text(pStmt, 1));
+ }
+ }else{
+ printf("ERROR: cannot query database: %s\n", sqlite3_errmsg(db));
}
- }else{
- printf("ERROR: cannot query database: %s\n", sqlite3_errmsg(db));
+ rc = sqlite3_finalize(pStmt);
+ if( rc==SQLITE_OK ) break;
}
- sqlite3_finalize(pStmt);
sqlite3_close(db);
/* Print the report and free memory used */
@@ -670,6 +697,53 @@ static void page_usage_report(const char *zDbName){
}
/*
+** Try to figure out how every page in the database file is being used.
+*/
+static void ptrmap_coverage_report(const char *zDbName){
+ unsigned int pgno;
+ unsigned char *aHdr;
+ unsigned char *a;
+ int usable;
+ int perPage;
+ unsigned int i;
+
+ /* Avoid the pathological case */
+ if( mxPage<1 ){
+ printf("empty database\n");
+ return;
+ }
+
+ /* Make sure PTRMAPs are used in this database */
+ aHdr = getContent(0, 100);
+ if( aHdr[55]==0 ){
+ printf("database does not use PTRMAP pages\n");
+ return;
+ }
+ usable = pagesize - aHdr[20];
+ perPage = usable/5;
+ free(aHdr);
+ printf("%5d: root of sqlite_master\n", 1);
+ for(pgno=2; pgno<=mxPage; pgno += perPage+1){
+ printf("%5d: PTRMAP page covering %d..%d\n", pgno,
+ pgno+1, pgno+perPage);
+ a = getContent((pgno-1)*pagesize, usable);
+ for(i=0; i+5<=usable && pgno+1+i/5<=mxPage; i+=5){
+ const char *zType = "???";
+ unsigned int iFrom = decodeInt32(&a[i+1]);
+ switch( a[i] ){
+ case 1: zType = "b-tree root page"; break;
+ case 2: zType = "freelist page"; break;
+ case 3: zType = "first page of overflow"; break;
+ case 4: zType = "later page of overflow"; break;
+ case 5: zType = "b-tree non-root page"; break;
+ }
+ printf("%5d: %s, parent=%u\n", pgno+1+i/5, zType, iFrom);
+ }
+ free(a);
+ }
+}
+
+/*
** Print a usage comment
*/
static void usage(const char *argv0){
@@ -678,6 +752,7 @@ static void usage(const char *argv0){
"args:\n"
" dbheader Show database header\n"
" pgidx Index of how each page is used\n"
+ " ptrmap Show all PTRMAP page content\n"
" NNN..MMM Show hex of pages NNN through MMM\n"
" NNN..end Show hex of pages NNN through end of file\n"
" NNNb Decode btree page NNN\n"
@@ -727,6 +802,14 @@ int main(int argc, char **argv){
page_usage_report(argv[1]);
continue;
}
+ if( strcmp(argv[i], "ptrmap")==0 ){
+ ptrmap_coverage_report(argv[1]);
+ continue;
+ }
+ if( strcmp(argv[i], "help")==0 ){
+ usage(argv[0]);
+ continue;
+ }
if( !isdigit(argv[i][0]) ){
fprintf(stderr, "%s: unknown option: [%s]\n", argv[0], argv[i]);
continue;