Add the "--uri" option to utility program "showdb". This option causes showdb to use sqlite with the SQLITE_OPEN_URI option to open the database file, instead of opening it directly using the OS open() function.

FossilOrigin-Name: 90e34d5119f720496e86a3a6de7771ea87b7dcbb
This commit is contained in:
dan
2015-08-03 17:03:31 +00:00
parent fa4620b6f5
commit 871f6e34f6
3 changed files with 235 additions and 117 deletions
+10 -7
View File
@@ -1,5 +1,5 @@
C Allow\sa\sVIEW\sto\sreference\sundefined\stables\sand\sfunctions\swhen\sinitially\ncreated.\s\sThe\serror\sreport\sis\sdeferred\suntil\sthe\sVIEW\sis\sused.\s\sThis\sallows\nviews\sto\sbe\screated\sbefore\ssubviews\sand\stables\sthat\sthe\sview\sreferences.
D 2015-08-03T13:44:45.941
C Add\sthe\s"--uri"\soption\sto\sutility\sprogram\s"showdb".\sThis\soption\scauses\sshowdb\sto\suse\ssqlite\swith\sthe\sSQLITE_OPEN_URI\soption\sto\sopen\sthe\sdatabase\sfile,\sinstead\sof\sopening\sit\sdirectly\susing\sthe\sOS\sopen()\sfunction.
D 2015-08-03T17:03:31.462
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 8b65966a80f30b95d3dcd9d7c13caaeb4dc21473
F tool/showjournal.c 053eb1cc774710c6890b7dd6293300cc297b16a5
F tool/showlocks.c 9920bcc64f58378ff1118caead34147201f48c68
F tool/showstat4.c 9515faa8ec176599d4a8288293ba8ec61f7b728a
@@ -1368,7 +1368,10 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
P 3419044967258e3ed65f71528e06952ee102dcc7
R a7ce110cce77b8da537a48fa80ac6f4f
U drh
Z 0cbd7829b00ada6a24c23b51a4093668
P 70b57dafb3216feb21091883196831fa1252e7bf
R 16122b1df3219db3f18abec519d4455c
T *branch * showdb-uri-option
T *sym-showdb-uri-option *
T -sym-trunk *
U dan
Z 0bf8c605dcc175d4e077bbfb11ad015a
+1 -1
View File
@@ -1 +1 @@
70b57dafb3216feb21091883196831fa1252e7bf
90e34d5119f720496e86a3a6de7771ea87b7dcbb
+224 -109
View File
@@ -15,13 +15,21 @@
#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 bUri; /* True for URI mode */
sqlite3_file *pFd; /* File descriptor for URI 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 +64,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.bUri ){
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.bUri ){
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.bUri ){
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.bUri ){
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 +204,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 +232,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 +373,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 +687,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 +717,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 +729,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 +755,7 @@ static void decode_trunk_page(
}else{
pgno = (int)decodeInt32(&a[0]);
}
free(a);
sqlite3_free(a);
}
}
@@ -669,9 +774,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 +824,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 +850,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 +888,7 @@ static void page_usage_btree(
page_usage_cell(a[hdr], a+ofst, pgno, i);
}
}
free(a);
sqlite3_free(a);
}
/*
@@ -797,9 +902,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 +912,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 +923,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 +937,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 +946,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 +986,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 +1006,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 +1037,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 +1045,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"
" --uri FILENAME is a URI\n"
"args:\n"
" dbheader Show database header\n"
" pgidx Index of how each page is used\n"
@@ -964,58 +1066,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("-uri", azArg[1])==0
|| sqlite3_stricmp("--uri", azArg[1])==0
){
g.bUri = 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(azArg[0], 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(azArg[0]);
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", azArg[0], 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 +1138,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 +1156,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 +1173,6 @@ int main(int argc, char **argv){
}
}
}
close(db);
fileClose();
return 0;
}