mirror of
https://github.com/sqlite/sqlite.git
synced 2026-01-06 08:01:16 +03:00
Update the [showdb] program so that the database file is read directly (bypassing the SQLite VFS) only if the --raw option is specified. Otherwise, it is read using the default VFS. Also, the URI syntax may be used on the command line to specify the name of the database file to examine, so an alternative VFS may be requested using a URI parameter.
FossilOrigin-Name: e3c6d4b6e738c7ea015c0c809a5f7d1a94dda945
This commit is contained in:
14
manifest
14
manifest
@@ -1,5 +1,5 @@
|
||||
C In\sthe\ssqlite3_analyzer.exe\sutility,\sshow\sthe\sdepth\sof\seach\sbtree\sand\sreport\nthe\saverage\sfanout\sof\sindexes\sand\sWITHOUT\sROWID\stables.
|
||||
D 2015-08-04T14:18:10.060
|
||||
C Update\sthe\s[showdb]\sprogram\sso\sthat\sthe\sdatabase\sfile\sis\sread\sdirectly\s(bypassing\sthe\sSQLite\sVFS)\sonly\sif\sthe\s--raw\soption\sis\sspecified.\sOtherwise,\sit\sis\sread\susing\sthe\sdefault\sVFS.\sAlso,\sthe\sURI\ssyntax\smay\sbe\sused\son\sthe\scommand\sline\sto\sspecify\sthe\sname\sof\sthe\sdatabase\sfile\sto\sexamine,\sso\san\salternative\sVFS\smay\sbe\srequested\susing\sa\sURI\sparameter.
|
||||
D 2015-08-04T15:29:43.068
|
||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||
F Makefile.in 4de3ef40c8b3b75c0c55ff4242a43c8ce1ad90ee
|
||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||
@@ -1343,7 +1343,7 @@ F tool/opcodeDoc.awk b3a2a3d5d3075b8bd90b7afe24283efdd586659c
|
||||
F tool/pagesig.c ff0ca355fd3c2398e933da5e22439bbff89b803b
|
||||
F tool/restore_jrnl.tcl 6957a34f8f1f0f8285e07536225ec3b292a9024a
|
||||
F tool/rollback-test.c 9fc98427d1e23e84429d7e6d07d9094fbdec65a5
|
||||
F tool/showdb.c 3b5d335d537e4dc44d0c86967023819453c87dc6
|
||||
F tool/showdb.c b1e16174385d5bd0815823a7fda1ecc82ed6088b
|
||||
F tool/showjournal.c 053eb1cc774710c6890b7dd6293300cc297b16a5
|
||||
F tool/showlocks.c 9920bcc64f58378ff1118caead34147201f48c68
|
||||
F tool/showstat4.c 9515faa8ec176599d4a8288293ba8ec61f7b728a
|
||||
@@ -1368,7 +1368,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
|
||||
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
|
||||
F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b
|
||||
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
|
||||
P 70b57dafb3216feb21091883196831fa1252e7bf
|
||||
R 13388672818fef0d2cb76a948959a6c9
|
||||
U drh
|
||||
Z 06142420513d4bba3f9f1464c1f7a39e
|
||||
P cd997770013e923ac3fa34b1546b97681923c8b1 9699e9bd9a0e813d04c9d37422920670697c46ed
|
||||
R 7b43c0477e767bd928070744aae8eca7
|
||||
U dan
|
||||
Z 8f4e8fe91dd9aa3d32924c08cf340019
|
||||
|
||||
@@ -1 +1 @@
|
||||
cd997770013e923ac3fa34b1546b97681923c8b1
|
||||
e3c6d4b6e738c7ea015c0c809a5f7d1a94dda945
|
||||
332
tool/showdb.c
332
tool/showdb.c
@@ -15,13 +15,20 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include "sqlite3.h"
|
||||
|
||||
|
||||
static int pagesize = 1024; /* Size of a database page */
|
||||
static int db = -1; /* File descriptor for reading the DB */
|
||||
static int mxPage = 0; /* Last page number */
|
||||
static int perLine = 16; /* HEX elements to print per line */
|
||||
static struct GlobalData {
|
||||
int pagesize; /* Size of a database page */
|
||||
int dbfd; /* File descriptor for reading the DB */
|
||||
int mxPage; /* Last page number */
|
||||
int perLine; /* HEX elements to print per line */
|
||||
int bRaw; /* True to access db file via OS APIs */
|
||||
sqlite3_file *pFd; /* File descriptor for non-raw mode */
|
||||
sqlite3 *pDb; /* Database handle that owns pFd */
|
||||
} g = {1024, -1, 0, 16, 0, 0, 0};
|
||||
|
||||
|
||||
typedef long long int i64; /* Datatype for 64-bit integers */
|
||||
|
||||
@@ -56,24 +63,122 @@ static void out_of_memory(void){
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
** Open a database connection.
|
||||
*/
|
||||
static sqlite3 *openDatabase(const char *zPrg, const char *zName){
|
||||
sqlite3 *db = 0;
|
||||
int flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_URI;
|
||||
int rc = sqlite3_open_v2(zName, &db, flags, 0);
|
||||
if( rc!=SQLITE_OK ){
|
||||
const char *zErr = sqlite3_errmsg(db);
|
||||
fprintf(stderr, "%s: can't open %s (%s)\n", zPrg, zName, zErr);
|
||||
sqlite3_close(db);
|
||||
exit(1);
|
||||
}
|
||||
return db;
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
** Beginning of low-level file access functions.
|
||||
**
|
||||
** All low-level access to the database file read by this program is
|
||||
** performed using the following four functions:
|
||||
**
|
||||
** fileOpen() - open the db file
|
||||
** fileClose() - close the db file
|
||||
** fileRead() - read raw data from the db file
|
||||
** fileGetsize() - return the size of the db file in bytes
|
||||
*/
|
||||
|
||||
/*
|
||||
** Open the database file.
|
||||
*/
|
||||
static void fileOpen(const char *zPrg, const char *zName){
|
||||
assert( g.dbfd<0 );
|
||||
if( g.bRaw==0 ){
|
||||
int rc;
|
||||
void *pArg = (void *)(&g.pFd);
|
||||
g.pDb = openDatabase(zPrg, zName);
|
||||
rc = sqlite3_file_control(g.pDb, "main", SQLITE_FCNTL_FILE_POINTER, pArg);
|
||||
if( rc!=SQLITE_OK ){
|
||||
fprintf(stderr,
|
||||
"%s: failed to obtain fd for %s (SQLite too old?)\n", zPrg, zName
|
||||
);
|
||||
exit(1);
|
||||
}
|
||||
}else{
|
||||
g.dbfd = open(zName, O_RDONLY);
|
||||
if( g.dbfd<0 ){
|
||||
fprintf(stderr,"%s: can't open %s\n", zPrg, zName);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Close the database file opened by fileOpen()
|
||||
*/
|
||||
static void fileClose(){
|
||||
if( g.bRaw==0 ){
|
||||
sqlite3_close(g.pDb);
|
||||
g.pDb = 0;
|
||||
g.pFd = 0;
|
||||
}else{
|
||||
close(g.dbfd);
|
||||
g.dbfd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Read content from the file.
|
||||
**
|
||||
** Space to hold the content is obtained from malloc() and needs to be
|
||||
** freed by the caller.
|
||||
** Space to hold the content is obtained from sqlite3_malloc() and needs
|
||||
** to be freed by the caller.
|
||||
*/
|
||||
static unsigned char *getContent(int ofst, int nByte){
|
||||
static unsigned char *fileRead(sqlite3_int64 ofst, int nByte){
|
||||
unsigned char *aData;
|
||||
int got;
|
||||
aData = malloc(nByte+32);
|
||||
aData = sqlite3_malloc(nByte+32);
|
||||
if( aData==0 ) out_of_memory();
|
||||
memset(aData, 0, nByte+32);
|
||||
lseek(db, ofst, SEEK_SET);
|
||||
got = read(db, aData, nByte);
|
||||
if( got>0 && got<nByte ) memset(aData+got, 0, nByte-got);
|
||||
if( g.bRaw==0 ){
|
||||
int rc = g.pFd->pMethods->xRead(g.pFd, (void*)aData, nByte, ofst);
|
||||
if( rc!=SQLITE_OK && rc!=SQLITE_IOERR_SHORT_READ ){
|
||||
fprintf(stderr, "error in xRead() - %d\n", rc);
|
||||
exit(1);
|
||||
}
|
||||
}else{
|
||||
lseek(g.dbfd, ofst, SEEK_SET);
|
||||
got = read(g.dbfd, aData, nByte);
|
||||
if( got>0 && got<nByte ) memset(aData+got, 0, nByte-got);
|
||||
}
|
||||
return aData;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the size of the file in byte.
|
||||
*/
|
||||
static sqlite3_int64 fileGetsize(void){
|
||||
sqlite3_int64 res = 0;
|
||||
if( g.bRaw==0 ){
|
||||
int rc = g.pFd->pMethods->xFileSize(g.pFd, &res);
|
||||
if( rc!=SQLITE_OK ){
|
||||
fprintf(stderr, "error in xFileSize() - %d\n", rc);
|
||||
exit(1);
|
||||
}
|
||||
}else{
|
||||
struct stat sbuf;
|
||||
fstat(g.dbfd, &sbuf);
|
||||
res = (sqlite3_int64)(sbuf.st_size);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
** End of low-level file access functions.
|
||||
**************************************************************************/
|
||||
|
||||
/*
|
||||
** Print a range of bytes as hex and as ascii.
|
||||
*/
|
||||
@@ -98,17 +203,17 @@ static unsigned char *print_byte_range(
|
||||
zOfstFmt = " %08x: ";
|
||||
}
|
||||
|
||||
aData = getContent(ofst, nByte);
|
||||
for(i=0; i<nByte; i += perLine){
|
||||
aData = fileRead(ofst, nByte);
|
||||
for(i=0; i<nByte; i += g.perLine){
|
||||
fprintf(stdout, zOfstFmt, i+printOfst);
|
||||
for(j=0; j<perLine; j++){
|
||||
for(j=0; j<g.perLine; j++){
|
||||
if( i+j>nByte ){
|
||||
fprintf(stdout, " ");
|
||||
}else{
|
||||
fprintf(stdout,"%02x ", aData[i+j]);
|
||||
}
|
||||
}
|
||||
for(j=0; j<perLine; j++){
|
||||
for(j=0; j<g.perLine; j++){
|
||||
if( i+j>nByte ){
|
||||
fprintf(stdout, " ");
|
||||
}else{
|
||||
@@ -126,11 +231,11 @@ static unsigned char *print_byte_range(
|
||||
static void print_page(int iPg){
|
||||
int iStart;
|
||||
unsigned char *aData;
|
||||
iStart = (iPg-1)*pagesize;
|
||||
iStart = (iPg-1)*g.pagesize;
|
||||
fprintf(stdout, "Page %d: (offsets 0x%x..0x%x)\n",
|
||||
iPg, iStart, iStart+pagesize-1);
|
||||
aData = print_byte_range(iStart, pagesize, 0);
|
||||
free(aData);
|
||||
iPg, iStart, iStart+g.pagesize-1);
|
||||
aData = print_byte_range(iStart, g.pagesize, 0);
|
||||
sqlite3_free(aData);
|
||||
}
|
||||
|
||||
|
||||
@@ -267,14 +372,14 @@ static i64 localPayload(i64 nPayload, char cType){
|
||||
i64 nLocal;
|
||||
if( cType==13 ){
|
||||
/* Table leaf */
|
||||
maxLocal = pagesize-35;
|
||||
minLocal = (pagesize-12)*32/255-23;
|
||||
maxLocal = g.pagesize-35;
|
||||
minLocal = (g.pagesize-12)*32/255-23;
|
||||
}else{
|
||||
maxLocal = (pagesize-12)*64/255-23;
|
||||
minLocal = (pagesize-12)*32/255-23;
|
||||
maxLocal = (g.pagesize-12)*64/255-23;
|
||||
minLocal = (g.pagesize-12)*32/255-23;
|
||||
}
|
||||
if( nPayload>maxLocal ){
|
||||
surplus = minLocal + (nPayload-minLocal)%(pagesize-4);
|
||||
surplus = minLocal + (nPayload-minLocal)%(g.pagesize-4);
|
||||
if( surplus<=maxLocal ){
|
||||
nLocal = surplus;
|
||||
}else{
|
||||
@@ -581,8 +686,8 @@ static void decode_btree_page(
|
||||
printf(" key: lx=left-child n=payload-size r=rowid\n");
|
||||
}
|
||||
if( showMap ){
|
||||
zMap = malloc(pagesize);
|
||||
memset(zMap, '.', pagesize);
|
||||
zMap = sqlite3_malloc(g.pagesize);
|
||||
memset(zMap, '.', g.pagesize);
|
||||
memset(zMap, '1', hdrSize);
|
||||
memset(&zMap[hdrSize], 'H', iCellPtr);
|
||||
memset(&zMap[hdrSize+iCellPtr], 'P', 2*nCell);
|
||||
@@ -611,10 +716,10 @@ static void decode_btree_page(
|
||||
}
|
||||
if( showMap ){
|
||||
printf("Page map: (H=header P=cell-index 1=page-1-header .=free-space)\n");
|
||||
for(i=0; i<pagesize; i+=64){
|
||||
for(i=0; i<g.pagesize; i+=64){
|
||||
printf(" %03x: %.64s\n", i, &zMap[i]);
|
||||
}
|
||||
free(zMap);
|
||||
sqlite3_free(zMap);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -623,14 +728,13 @@ static void decode_btree_page(
|
||||
*/
|
||||
static void decode_trunk_page(
|
||||
int pgno, /* The page number */
|
||||
int pagesize, /* Size of each page */
|
||||
int detail, /* Show leaf pages if true */
|
||||
int recursive /* Follow the trunk change if true */
|
||||
){
|
||||
int n, i;
|
||||
unsigned char *a;
|
||||
while( pgno>0 ){
|
||||
a = getContent((pgno-1)*pagesize, pagesize);
|
||||
a = fileRead((pgno-1)*g.pagesize, g.pagesize);
|
||||
printf("Decode of freelist trunk page %d:\n", pgno);
|
||||
print_decode_line(a, 0, 4, "Next freelist trunk page");
|
||||
print_decode_line(a, 4, 4, "Number of entries on this page");
|
||||
@@ -650,7 +754,7 @@ static void decode_trunk_page(
|
||||
}else{
|
||||
pgno = (int)decodeInt32(&a[0]);
|
||||
}
|
||||
free(a);
|
||||
sqlite3_free(a);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -669,9 +773,9 @@ static void page_usage_msg(int pgno, const char *zFormat, ...){
|
||||
va_start(ap, zFormat);
|
||||
zMsg = sqlite3_vmprintf(zFormat, ap);
|
||||
va_end(ap);
|
||||
if( pgno<=0 || pgno>mxPage ){
|
||||
if( pgno<=0 || pgno>g.mxPage ){
|
||||
printf("ERROR: page %d out of range 1..%d: %s\n",
|
||||
pgno, mxPage, zMsg);
|
||||
pgno, g.mxPage, zMsg);
|
||||
sqlite3_free(zMsg);
|
||||
return;
|
||||
}
|
||||
@@ -719,12 +823,12 @@ static void page_usage_cell(
|
||||
if( nLocal<nPayload ){
|
||||
int ovfl = decodeInt32(a+nLocal);
|
||||
int cnt = 0;
|
||||
while( ovfl && (cnt++)<mxPage ){
|
||||
while( ovfl && (cnt++)<g.mxPage ){
|
||||
page_usage_msg(ovfl, "overflow %d from cell %d of page %d",
|
||||
cnt, cellno, pgno);
|
||||
a = getContent((ovfl-1)*pagesize, 4);
|
||||
a = fileRead((ovfl-1)*g.pagesize, 4);
|
||||
ovfl = decodeInt32(a);
|
||||
free(a);
|
||||
sqlite3_free(a);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -745,8 +849,8 @@ static void page_usage_btree(
|
||||
int i;
|
||||
int hdr = pgno==1 ? 100 : 0;
|
||||
|
||||
if( pgno<=0 || pgno>mxPage ) return;
|
||||
a = getContent((pgno-1)*pagesize, pagesize);
|
||||
if( pgno<=0 || pgno>g.mxPage ) return;
|
||||
a = fileRead((pgno-1)*g.pagesize, g.pagesize);
|
||||
switch( a[hdr] ){
|
||||
case 2: zType = "interior node of index"; break;
|
||||
case 5: zType = "interior node of table"; break;
|
||||
@@ -783,7 +887,7 @@ static void page_usage_btree(
|
||||
page_usage_cell(a[hdr], a+ofst, pgno, i);
|
||||
}
|
||||
}
|
||||
free(a);
|
||||
sqlite3_free(a);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -797,9 +901,9 @@ static void page_usage_freelist(int pgno){
|
||||
int iNext;
|
||||
int parent = 1;
|
||||
|
||||
while( pgno>0 && pgno<=mxPage && (cnt++)<mxPage ){
|
||||
while( pgno>0 && pgno<=g.mxPage && (cnt++)<g.mxPage ){
|
||||
page_usage_msg(pgno, "freelist trunk #%d child of %d", cnt, parent);
|
||||
a = getContent((pgno-1)*pagesize, pagesize);
|
||||
a = fileRead((pgno-1)*g.pagesize, g.pagesize);
|
||||
iNext = decodeInt32(a);
|
||||
n = decodeInt32(a+4);
|
||||
for(i=0; i<n; i++){
|
||||
@@ -807,7 +911,7 @@ static void page_usage_freelist(int pgno){
|
||||
page_usage_msg(child, "freelist leaf, child %d of trunk page %d",
|
||||
i, pgno);
|
||||
}
|
||||
free(a);
|
||||
sqlite3_free(a);
|
||||
parent = pgno;
|
||||
pgno = iNext;
|
||||
}
|
||||
@@ -818,10 +922,10 @@ static void page_usage_freelist(int pgno){
|
||||
*/
|
||||
static void page_usage_ptrmap(unsigned char *a){
|
||||
if( a[55] ){
|
||||
int usable = pagesize - a[20];
|
||||
int usable = g.pagesize - a[20];
|
||||
int pgno = 2;
|
||||
int perPage = usable/5;
|
||||
while( pgno<=mxPage ){
|
||||
while( pgno<=g.mxPage ){
|
||||
page_usage_msg(pgno, "PTRMAP page covering %d..%d",
|
||||
pgno+1, pgno+perPage);
|
||||
pgno += perPage + 1;
|
||||
@@ -832,7 +936,7 @@ static void page_usage_ptrmap(unsigned char *a){
|
||||
/*
|
||||
** Try to figure out how every page in the database file is being used.
|
||||
*/
|
||||
static void page_usage_report(const char *zDbName){
|
||||
static void page_usage_report(const char *zPrg, const char *zDbName){
|
||||
int i, j;
|
||||
int rc;
|
||||
sqlite3 *db;
|
||||
@@ -841,30 +945,25 @@ static void page_usage_report(const char *zDbName){
|
||||
char zQuery[200];
|
||||
|
||||
/* Avoid the pathological case */
|
||||
if( mxPage<1 ){
|
||||
if( g.mxPage<1 ){
|
||||
printf("empty database\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Open the database file */
|
||||
rc = sqlite3_open(zDbName, &db);
|
||||
if( rc ){
|
||||
printf("cannot open database: %s\n", sqlite3_errmsg(db));
|
||||
sqlite3_close(db);
|
||||
return;
|
||||
}
|
||||
db = openDatabase(zPrg, zDbName);
|
||||
|
||||
/* Set up global variables zPageUse[] and mxPage to record page
|
||||
/* Set up global variables zPageUse[] and g.mxPage to record page
|
||||
** usages */
|
||||
zPageUse = sqlite3_malloc( sizeof(zPageUse[0])*(mxPage+1) );
|
||||
zPageUse = sqlite3_malloc( sizeof(zPageUse[0])*(g.mxPage+1) );
|
||||
if( zPageUse==0 ) out_of_memory();
|
||||
memset(zPageUse, 0, sizeof(zPageUse[0])*(mxPage+1));
|
||||
memset(zPageUse, 0, sizeof(zPageUse[0])*(g.mxPage+1));
|
||||
|
||||
/* Discover the usage of each page */
|
||||
a = getContent(0, 100);
|
||||
a = fileRead(0, 100);
|
||||
page_usage_freelist(decodeInt32(a+32));
|
||||
page_usage_ptrmap(a);
|
||||
free(a);
|
||||
sqlite3_free(a);
|
||||
page_usage_btree(1, 0, 0, "sqlite_master");
|
||||
sqlite3_exec(db, "PRAGMA writable_schema=ON", 0, 0, 0);
|
||||
for(j=0; j<2; j++){
|
||||
@@ -886,7 +985,7 @@ static void page_usage_report(const char *zDbName){
|
||||
sqlite3_close(db);
|
||||
|
||||
/* Print the report and free memory used */
|
||||
for(i=1; i<=mxPage; i++){
|
||||
for(i=1; i<=g.mxPage; i++){
|
||||
printf("%5d: %s\n", i, zPageUse[i] ? zPageUse[i] : "???");
|
||||
sqlite3_free(zPageUse[i]);
|
||||
}
|
||||
@@ -906,26 +1005,26 @@ static void ptrmap_coverage_report(const char *zDbName){
|
||||
int i;
|
||||
|
||||
/* Avoid the pathological case */
|
||||
if( mxPage<1 ){
|
||||
if( g.mxPage<1 ){
|
||||
printf("empty database\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Make sure PTRMAPs are used in this database */
|
||||
aHdr = getContent(0, 100);
|
||||
aHdr = fileRead(0, 100);
|
||||
if( aHdr[55]==0 ){
|
||||
printf("database does not use PTRMAP pages\n");
|
||||
return;
|
||||
}
|
||||
usable = pagesize - aHdr[20];
|
||||
usable = g.pagesize - aHdr[20];
|
||||
perPage = usable/5;
|
||||
free(aHdr);
|
||||
sqlite3_free(aHdr);
|
||||
printf("%5d: root of sqlite_master\n", 1);
|
||||
for(pgno=2; pgno<=mxPage; pgno += perPage+1){
|
||||
for(pgno=2; pgno<=g.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){
|
||||
a = fileRead((pgno-1)*g.pagesize, usable);
|
||||
for(i=0; i+5<=usable && pgno+1+i/5<=g.mxPage; i+=5){
|
||||
const char *zType = "???";
|
||||
unsigned int iFrom = decodeInt32(&a[i+1]);
|
||||
switch( a[i] ){
|
||||
@@ -937,7 +1036,7 @@ static void ptrmap_coverage_report(const char *zDbName){
|
||||
}
|
||||
printf("%5d: %s, parent=%u\n", pgno+1+i/5, zType, iFrom);
|
||||
}
|
||||
free(a);
|
||||
sqlite3_free(a);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -945,8 +1044,10 @@ static void ptrmap_coverage_report(const char *zDbName){
|
||||
** Print a usage comment
|
||||
*/
|
||||
static void usage(const char *argv0){
|
||||
fprintf(stderr, "Usage %s FILENAME ?args...?\n\n", argv0);
|
||||
fprintf(stderr, "Usage %s ?--uri? FILENAME ?args...?\n\n", argv0);
|
||||
fprintf(stderr,
|
||||
"switches:\n"
|
||||
" --raw Read db file directly, bypassing SQLite VFS\n"
|
||||
"args:\n"
|
||||
" dbheader Show database header\n"
|
||||
" pgidx Index of how each page is used\n"
|
||||
@@ -964,58 +1065,71 @@ static void usage(const char *argv0){
|
||||
}
|
||||
|
||||
int main(int argc, char **argv){
|
||||
struct stat sbuf;
|
||||
unsigned char zPgSz[2];
|
||||
if( argc<2 ){
|
||||
usage(argv[0]);
|
||||
sqlite3_int64 szFile;
|
||||
unsigned char *zPgSz;
|
||||
const char *zPrg = argv[0]; /* Name of this executable */
|
||||
char **azArg = argv;
|
||||
int nArg = argc;
|
||||
|
||||
/* Check for the "--uri" or "-uri" switch. */
|
||||
if( nArg>1 ){
|
||||
if( sqlite3_stricmp("-raw", azArg[1])==0
|
||||
|| sqlite3_stricmp("--raw", azArg[1])==0
|
||||
){
|
||||
g.bRaw = 1;
|
||||
azArg++;
|
||||
nArg--;
|
||||
}
|
||||
}
|
||||
|
||||
if( nArg<2 ){
|
||||
usage(zPrg);
|
||||
exit(1);
|
||||
}
|
||||
db = open(argv[1], O_RDONLY);
|
||||
if( db<0 ){
|
||||
fprintf(stderr,"%s: can't open %s\n", argv[0], argv[1]);
|
||||
exit(1);
|
||||
}
|
||||
zPgSz[0] = 0;
|
||||
zPgSz[1] = 0;
|
||||
lseek(db, 16, SEEK_SET);
|
||||
if( read(db, zPgSz, 2)<2 ) memset(zPgSz, 0, 2);
|
||||
pagesize = zPgSz[0]*256 + zPgSz[1]*65536;
|
||||
if( pagesize==0 ) pagesize = 1024;
|
||||
printf("Pagesize: %d\n", pagesize);
|
||||
fstat(db, &sbuf);
|
||||
mxPage = (sbuf.st_size+pagesize-1)/pagesize;
|
||||
printf("Available pages: 1..%d\n", mxPage);
|
||||
if( argc==2 ){
|
||||
|
||||
fileOpen(zPrg, azArg[1]);
|
||||
szFile = fileGetsize();
|
||||
|
||||
zPgSz = fileRead(16, 2);
|
||||
g.pagesize = zPgSz[0]*256 + zPgSz[1]*65536;
|
||||
if( g.pagesize==0 ) g.pagesize = 1024;
|
||||
sqlite3_free(zPgSz);
|
||||
|
||||
printf("Pagesize: %d\n", g.pagesize);
|
||||
g.mxPage = (szFile+g.pagesize-1)/g.pagesize;
|
||||
|
||||
printf("Available pages: 1..%d\n", g.mxPage);
|
||||
if( nArg==2 ){
|
||||
int i;
|
||||
for(i=1; i<=mxPage; i++) print_page(i);
|
||||
for(i=1; i<=g.mxPage; i++) print_page(i);
|
||||
}else{
|
||||
int i;
|
||||
for(i=2; i<argc; i++){
|
||||
for(i=2; i<nArg; i++){
|
||||
int iStart, iEnd;
|
||||
char *zLeft;
|
||||
if( strcmp(argv[i], "dbheader")==0 ){
|
||||
if( strcmp(azArg[i], "dbheader")==0 ){
|
||||
print_db_header();
|
||||
continue;
|
||||
}
|
||||
if( strcmp(argv[i], "pgidx")==0 ){
|
||||
page_usage_report(argv[1]);
|
||||
if( strcmp(azArg[i], "pgidx")==0 ){
|
||||
page_usage_report(zPrg, azArg[1]);
|
||||
continue;
|
||||
}
|
||||
if( strcmp(argv[i], "ptrmap")==0 ){
|
||||
ptrmap_coverage_report(argv[1]);
|
||||
if( strcmp(azArg[i], "ptrmap")==0 ){
|
||||
ptrmap_coverage_report(azArg[1]);
|
||||
continue;
|
||||
}
|
||||
if( strcmp(argv[i], "help")==0 ){
|
||||
usage(argv[0]);
|
||||
if( strcmp(azArg[i], "help")==0 ){
|
||||
usage(zPrg);
|
||||
continue;
|
||||
}
|
||||
if( !isdigit(argv[i][0]) ){
|
||||
fprintf(stderr, "%s: unknown option: [%s]\n", argv[0], argv[i]);
|
||||
if( !isdigit(azArg[i][0]) ){
|
||||
fprintf(stderr, "%s: unknown option: [%s]\n", zPrg, azArg[i]);
|
||||
continue;
|
||||
}
|
||||
iStart = strtol(argv[i], &zLeft, 0);
|
||||
iStart = strtol(azArg[i], &zLeft, 0);
|
||||
if( zLeft && strcmp(zLeft,"..end")==0 ){
|
||||
iEnd = mxPage;
|
||||
iEnd = g.mxPage;
|
||||
}else if( zLeft && zLeft[0]=='.' && zLeft[1]=='.' ){
|
||||
iEnd = strtol(&zLeft[2], 0, 0);
|
||||
}else if( zLeft && zLeft[0]=='b' ){
|
||||
@@ -1023,15 +1137,15 @@ int main(int argc, char **argv){
|
||||
unsigned char *a;
|
||||
if( iStart==1 ){
|
||||
ofst = hdrSize = 100;
|
||||
nByte = pagesize-100;
|
||||
nByte = g.pagesize-100;
|
||||
}else{
|
||||
hdrSize = 0;
|
||||
ofst = (iStart-1)*pagesize;
|
||||
nByte = pagesize;
|
||||
ofst = (iStart-1)*g.pagesize;
|
||||
nByte = g.pagesize;
|
||||
}
|
||||
a = getContent(ofst, nByte);
|
||||
a = fileRead(ofst, nByte);
|
||||
decode_btree_page(a, iStart, hdrSize, &zLeft[1]);
|
||||
free(a);
|
||||
sqlite3_free(a);
|
||||
continue;
|
||||
}else if( zLeft && zLeft[0]=='t' ){
|
||||
int detail = 0;
|
||||
@@ -1041,15 +1155,15 @@ int main(int argc, char **argv){
|
||||
if( zLeft[i]=='r' ) recursive = 1;
|
||||
if( zLeft[i]=='d' ) detail = 1;
|
||||
}
|
||||
decode_trunk_page(iStart, pagesize, detail, recursive);
|
||||
decode_trunk_page(iStart, detail, recursive);
|
||||
continue;
|
||||
}else{
|
||||
iEnd = iStart;
|
||||
}
|
||||
if( iStart<1 || iEnd<iStart || iEnd>mxPage ){
|
||||
if( iStart<1 || iEnd<iStart || iEnd>g.mxPage ){
|
||||
fprintf(stderr,
|
||||
"Page argument should be LOWER?..UPPER?. Range 1 to %d\n",
|
||||
mxPage);
|
||||
g.mxPage);
|
||||
exit(1);
|
||||
}
|
||||
while( iStart<=iEnd ){
|
||||
@@ -1058,6 +1172,6 @@ int main(int argc, char **argv){
|
||||
}
|
||||
}
|
||||
}
|
||||
close(db);
|
||||
fileClose();
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user