blob: 611e603fe900bbd4d429fdf7eba695e1d7060014 [file] [log] [blame]
drh0de8c112002-07-06 16:32:14 +00001/*
2** A utility for printing all or part of an SQLite database file.
3*/
4#include <stdio.h>
5#include <ctype.h>
drhc56fac72015-10-29 13:48:15 +00006#define ISDIGIT(X) isdigit((unsigned char)(X))
7#define ISPRINT(X) isprint((unsigned char)(X))
drh0de8c112002-07-06 16:32:14 +00008#include <sys/types.h>
9#include <sys/stat.h>
10#include <fcntl.h>
mistachkin026262b2012-10-13 09:31:20 +000011
12#if !defined(_MSC_VER)
drh0de8c112002-07-06 16:32:14 +000013#include <unistd.h>
mistachkin0461cc42014-07-18 21:16:37 +000014#else
15#include <io.h>
mistachkin026262b2012-10-13 09:31:20 +000016#endif
17
drh0de8c112002-07-06 16:32:14 +000018#include <stdlib.h>
drh562cedb2010-04-26 15:44:07 +000019#include <string.h>
dan871f6e32015-08-03 17:03:31 +000020#include <assert.h>
drh3aeea462012-04-03 14:59:50 +000021#include "sqlite3.h"
drh0de8c112002-07-06 16:32:14 +000022
drh55550b72020-07-22 11:42:50 +000023typedef unsigned char u8; /* unsigned 8-bit */
24typedef unsigned int u32; /* unsigned 32-bit */
25typedef sqlite3_int64 i64; /* signed 64-bit */
26typedef sqlite3_uint64 u64; /* unsigned 64-bit */
27
drh0de8c112002-07-06 16:32:14 +000028
dan871f6e32015-08-03 17:03:31 +000029static struct GlobalData {
drh55550b72020-07-22 11:42:50 +000030 u32 pagesize; /* Size of a database page */
dan871f6e32015-08-03 17:03:31 +000031 int dbfd; /* File descriptor for reading the DB */
drh55550b72020-07-22 11:42:50 +000032 u32 mxPage; /* Last page number */
dan871f6e32015-08-03 17:03:31 +000033 int perLine; /* HEX elements to print per line */
dan8fb1bd22015-08-04 15:23:49 +000034 int bRaw; /* True to access db file via OS APIs */
dan30c16ad2015-08-04 15:29:43 +000035 sqlite3_file *pFd; /* File descriptor for non-raw mode */
dan871f6e32015-08-03 17:03:31 +000036 sqlite3 *pDb; /* Database handle that owns pFd */
37} g = {1024, -1, 0, 16, 0, 0, 0};
38
drh562cedb2010-04-26 15:44:07 +000039/*
40** Convert the var-int format into i64. Return the number of bytes
41** in the var-int. Write the var-int value into *pVal.
42*/
drh7ecc1472010-04-26 16:47:12 +000043static int decodeVarint(const unsigned char *z, i64 *pVal){
drh562cedb2010-04-26 15:44:07 +000044 i64 v = 0;
drh7ecc1472010-04-26 16:47:12 +000045 int i;
46 for(i=0; i<8; i++){
drh562cedb2010-04-26 15:44:07 +000047 v = (v<<7) + (z[i]&0x7f);
48 if( (z[i]&0x80)==0 ){ *pVal = v; return i+1; }
49 }
50 v = (v<<8) + (z[i]&0xff);
51 *pVal = v;
52 return 9;
53}
54
drh7d105f82010-08-23 15:26:49 +000055/*
56** Extract a big-endian 32-bit integer
57*/
drh55550b72020-07-22 11:42:50 +000058static u32 decodeInt32(const u8 *z){
drh7d105f82010-08-23 15:26:49 +000059 return (z[0]<<24) + (z[1]<<16) + (z[2]<<8) + z[3];
60}
61
drh562cedb2010-04-26 15:44:07 +000062/* Report an out-of-memory error and die.
63*/
drh0de8c112002-07-06 16:32:14 +000064static void out_of_memory(void){
65 fprintf(stderr,"Out of memory...\n");
66 exit(1);
67}
68
drh562cedb2010-04-26 15:44:07 +000069/*
dan871f6e32015-08-03 17:03:31 +000070** Open a database connection.
71*/
72static sqlite3 *openDatabase(const char *zPrg, const char *zName){
73 sqlite3 *db = 0;
74 int flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_URI;
75 int rc = sqlite3_open_v2(zName, &db, flags, 0);
76 if( rc!=SQLITE_OK ){
77 const char *zErr = sqlite3_errmsg(db);
78 fprintf(stderr, "%s: can't open %s (%s)\n", zPrg, zName, zErr);
79 sqlite3_close(db);
80 exit(1);
81 }
82 return db;
83}
84
85/**************************************************************************
86** Beginning of low-level file access functions.
87**
88** All low-level access to the database file read by this program is
89** performed using the following four functions:
90**
91** fileOpen() - open the db file
92** fileClose() - close the db file
93** fileRead() - read raw data from the db file
94** fileGetsize() - return the size of the db file in bytes
95*/
96
97/*
98** Open the database file.
99*/
100static void fileOpen(const char *zPrg, const char *zName){
101 assert( g.dbfd<0 );
dan8fb1bd22015-08-04 15:23:49 +0000102 if( g.bRaw==0 ){
dan871f6e32015-08-03 17:03:31 +0000103 int rc;
104 void *pArg = (void *)(&g.pFd);
105 g.pDb = openDatabase(zPrg, zName);
106 rc = sqlite3_file_control(g.pDb, "main", SQLITE_FCNTL_FILE_POINTER, pArg);
107 if( rc!=SQLITE_OK ){
108 fprintf(stderr,
109 "%s: failed to obtain fd for %s (SQLite too old?)\n", zPrg, zName
110 );
111 exit(1);
112 }
113 }else{
114 g.dbfd = open(zName, O_RDONLY);
115 if( g.dbfd<0 ){
116 fprintf(stderr,"%s: can't open %s\n", zPrg, zName);
117 exit(1);
118 }
119 }
120}
121
122/*
123** Close the database file opened by fileOpen()
124*/
125static void fileClose(){
dan8fb1bd22015-08-04 15:23:49 +0000126 if( g.bRaw==0 ){
dan871f6e32015-08-03 17:03:31 +0000127 sqlite3_close(g.pDb);
128 g.pDb = 0;
129 g.pFd = 0;
130 }else{
131 close(g.dbfd);
132 g.dbfd = -1;
133 }
134}
135
136/*
drh562cedb2010-04-26 15:44:07 +0000137** Read content from the file.
138**
dan871f6e32015-08-03 17:03:31 +0000139** Space to hold the content is obtained from sqlite3_malloc() and needs
140** to be freed by the caller.
drh562cedb2010-04-26 15:44:07 +0000141*/
dan871f6e32015-08-03 17:03:31 +0000142static unsigned char *fileRead(sqlite3_int64 ofst, int nByte){
drh562cedb2010-04-26 15:44:07 +0000143 unsigned char *aData;
drh748c7352015-04-15 15:29:05 +0000144 int got;
drh55550b72020-07-22 11:42:50 +0000145 aData = sqlite3_malloc64(32+(i64)nByte);
drh562cedb2010-04-26 15:44:07 +0000146 if( aData==0 ) out_of_memory();
drhb7787ee2011-01-06 15:51:18 +0000147 memset(aData, 0, nByte+32);
dan8fb1bd22015-08-04 15:23:49 +0000148 if( g.bRaw==0 ){
dan871f6e32015-08-03 17:03:31 +0000149 int rc = g.pFd->pMethods->xRead(g.pFd, (void*)aData, nByte, ofst);
150 if( rc!=SQLITE_OK && rc!=SQLITE_IOERR_SHORT_READ ){
151 fprintf(stderr, "error in xRead() - %d\n", rc);
152 exit(1);
153 }
154 }else{
mistachkin77fac872016-04-12 20:05:06 +0000155 lseek(g.dbfd, (long)ofst, SEEK_SET);
dan871f6e32015-08-03 17:03:31 +0000156 got = read(g.dbfd, aData, nByte);
157 if( got>0 && got<nByte ) memset(aData+got, 0, nByte-got);
158 }
drh562cedb2010-04-26 15:44:07 +0000159 return aData;
160}
161
162/*
dan871f6e32015-08-03 17:03:31 +0000163** Return the size of the file in byte.
164*/
drh55550b72020-07-22 11:42:50 +0000165static i64 fileGetsize(void){
166 i64 res = 0;
dan8fb1bd22015-08-04 15:23:49 +0000167 if( g.bRaw==0 ){
dan871f6e32015-08-03 17:03:31 +0000168 int rc = g.pFd->pMethods->xFileSize(g.pFd, &res);
169 if( rc!=SQLITE_OK ){
170 fprintf(stderr, "error in xFileSize() - %d\n", rc);
171 exit(1);
172 }
173 }else{
174 struct stat sbuf;
175 fstat(g.dbfd, &sbuf);
176 res = (sqlite3_int64)(sbuf.st_size);
177 }
178 return res;
179}
180
181/*
182** End of low-level file access functions.
183**************************************************************************/
184
185/*
drh562cedb2010-04-26 15:44:07 +0000186** Print a range of bytes as hex and as ascii.
187*/
188static unsigned char *print_byte_range(
drh55550b72020-07-22 11:42:50 +0000189 sqlite3_int64 ofst, /* First byte in the range of bytes to print */
190 int nByte, /* Number of bytes to print */
191 int printOfst /* Add this amount to the index on the left column */
drh562cedb2010-04-26 15:44:07 +0000192){
drh0de8c112002-07-06 16:32:14 +0000193 unsigned char *aData;
194 int i, j;
drh562cedb2010-04-26 15:44:07 +0000195 const char *zOfstFmt;
196
197 if( ((printOfst+nByte)&~0xfff)==0 ){
198 zOfstFmt = " %03x: ";
199 }else if( ((printOfst+nByte)&~0xffff)==0 ){
200 zOfstFmt = " %04x: ";
201 }else if( ((printOfst+nByte)&~0xfffff)==0 ){
202 zOfstFmt = " %05x: ";
203 }else if( ((printOfst+nByte)&~0xffffff)==0 ){
204 zOfstFmt = " %06x: ";
205 }else{
206 zOfstFmt = " %08x: ";
207 }
208
dan871f6e32015-08-03 17:03:31 +0000209 aData = fileRead(ofst, nByte);
210 for(i=0; i<nByte; i += g.perLine){
drh55550b72020-07-22 11:42:50 +0000211 int go = 0;
212 for(j=0; j<g.perLine; j++){
213 if( i+j>nByte ){ break; }
214 if( aData[i+j] ){ go = 1; break; }
215 }
216 if( !go && i>0 && i+g.perLine<nByte ) continue;
drh562cedb2010-04-26 15:44:07 +0000217 fprintf(stdout, zOfstFmt, i+printOfst);
dan871f6e32015-08-03 17:03:31 +0000218 for(j=0; j<g.perLine; j++){
drh562cedb2010-04-26 15:44:07 +0000219 if( i+j>nByte ){
220 fprintf(stdout, " ");
221 }else{
222 fprintf(stdout,"%02x ", aData[i+j]);
223 }
drh0de8c112002-07-06 16:32:14 +0000224 }
dan871f6e32015-08-03 17:03:31 +0000225 for(j=0; j<g.perLine; j++){
drh562cedb2010-04-26 15:44:07 +0000226 if( i+j>nByte ){
227 fprintf(stdout, " ");
228 }else{
drhc56fac72015-10-29 13:48:15 +0000229 fprintf(stdout,"%c", ISPRINT(aData[i+j]) ? aData[i+j] : '.');
drh562cedb2010-04-26 15:44:07 +0000230 }
drh0de8c112002-07-06 16:32:14 +0000231 }
232 fprintf(stdout,"\n");
233 }
drh562cedb2010-04-26 15:44:07 +0000234 return aData;
235}
236
237/*
238** Print an entire page of content as hex
239*/
drh55550b72020-07-22 11:42:50 +0000240static void print_page(u32 iPg){
241 i64 iStart;
drh562cedb2010-04-26 15:44:07 +0000242 unsigned char *aData;
drh55550b72020-07-22 11:42:50 +0000243 iStart = ((i64)(iPg-1))*g.pagesize;
244 fprintf(stdout, "Page %u: (offsets 0x%llx..0x%llx)\n",
dan871f6e32015-08-03 17:03:31 +0000245 iPg, iStart, iStart+g.pagesize-1);
246 aData = print_byte_range(iStart, g.pagesize, 0);
247 sqlite3_free(aData);
drh0de8c112002-07-06 16:32:14 +0000248}
249
drh6a30cd52014-06-19 23:38:53 +0000250
drh55550b72020-07-22 11:42:50 +0000251/* Print a line of decoded output showing a 4-byte unsigned integer.
drh562cedb2010-04-26 15:44:07 +0000252*/
drhdb718d82014-01-28 20:36:22 +0000253static void print_decode_line(
drh562cedb2010-04-26 15:44:07 +0000254 unsigned char *aData, /* Content being decoded */
255 int ofst, int nByte, /* Start and size of decode */
256 const char *zMsg /* Message to append */
257){
258 int i, j;
drh55550b72020-07-22 11:42:50 +0000259 u32 val = aData[ofst];
drh562cedb2010-04-26 15:44:07 +0000260 char zBuf[100];
261 sprintf(zBuf, " %03x: %02x", ofst, aData[ofst]);
mistachkinef607032014-07-19 15:40:39 +0000262 i = (int)strlen(zBuf);
drh562cedb2010-04-26 15:44:07 +0000263 for(j=1; j<4; j++){
264 if( j>=nByte ){
265 sprintf(&zBuf[i], " ");
266 }else{
267 sprintf(&zBuf[i], " %02x", aData[ofst+j]);
268 val = val*256 + aData[ofst+j];
269 }
mistachkinef607032014-07-19 15:40:39 +0000270 i += (int)strlen(&zBuf[i]);
drh562cedb2010-04-26 15:44:07 +0000271 }
drh55550b72020-07-22 11:42:50 +0000272 sprintf(&zBuf[i], " %10u", val);
drh7ecc1472010-04-26 16:47:12 +0000273 printf("%s %s\n", zBuf, zMsg);
drh562cedb2010-04-26 15:44:07 +0000274}
275
276/*
277** Decode the database header.
278*/
drh7ecc1472010-04-26 16:47:12 +0000279static void print_db_header(void){
drh562cedb2010-04-26 15:44:07 +0000280 unsigned char *aData;
281 aData = print_byte_range(0, 100, 0);
282 printf("Decoded:\n");
283 print_decode_line(aData, 16, 2, "Database page size");
284 print_decode_line(aData, 18, 1, "File format write version");
285 print_decode_line(aData, 19, 1, "File format read version");
286 print_decode_line(aData, 20, 1, "Reserved space at end of page");
287 print_decode_line(aData, 24, 4, "File change counter");
288 print_decode_line(aData, 28, 4, "Size of database in pages");
289 print_decode_line(aData, 32, 4, "Page number of first freelist page");
290 print_decode_line(aData, 36, 4, "Number of freelist pages");
291 print_decode_line(aData, 40, 4, "Schema cookie");
292 print_decode_line(aData, 44, 4, "Schema format version");
293 print_decode_line(aData, 48, 4, "Default page cache size");
294 print_decode_line(aData, 52, 4, "Largest auto-vac root page");
295 print_decode_line(aData, 56, 4, "Text encoding");
296 print_decode_line(aData, 60, 4, "User version");
297 print_decode_line(aData, 64, 4, "Incremental-vacuum mode");
drh4ee09b42013-05-01 19:49:27 +0000298 print_decode_line(aData, 68, 4, "Application ID");
drh562cedb2010-04-26 15:44:07 +0000299 print_decode_line(aData, 72, 4, "meta[8]");
300 print_decode_line(aData, 76, 4, "meta[9]");
301 print_decode_line(aData, 80, 4, "meta[10]");
302 print_decode_line(aData, 84, 4, "meta[11]");
303 print_decode_line(aData, 88, 4, "meta[12]");
drhb28e59b2010-06-17 02:13:39 +0000304 print_decode_line(aData, 92, 4, "Change counter for version number");
drhc6d2b4a2010-04-26 17:30:52 +0000305 print_decode_line(aData, 96, 4, "SQLite version number");
drh55550b72020-07-22 11:42:50 +0000306 sqlite3_free(aData);
drh562cedb2010-04-26 15:44:07 +0000307}
308
drh7ecc1472010-04-26 16:47:12 +0000309/*
drh100335b2011-01-05 21:20:52 +0000310** Describe cell content.
311*/
mistachkin0461cc42014-07-18 21:16:37 +0000312static i64 describeContent(
drh5240aeb2011-01-06 01:26:38 +0000313 unsigned char *a, /* Cell content */
mistachkin0461cc42014-07-18 21:16:37 +0000314 i64 nLocal, /* Bytes in a[] */
drh5240aeb2011-01-06 01:26:38 +0000315 char *zDesc /* Write description here */
drh100335b2011-01-05 21:20:52 +0000316){
mistachkin0461cc42014-07-18 21:16:37 +0000317 i64 nDesc = 0;
318 int n, j;
319 i64 i, x, v;
drh100335b2011-01-05 21:20:52 +0000320 const unsigned char *pData;
drh5240aeb2011-01-06 01:26:38 +0000321 const unsigned char *pLimit;
drh100335b2011-01-05 21:20:52 +0000322 char sep = ' ';
323
drh5240aeb2011-01-06 01:26:38 +0000324 pLimit = &a[nLocal];
drh100335b2011-01-05 21:20:52 +0000325 n = decodeVarint(a, &x);
326 pData = &a[x];
327 a += n;
328 i = x - n;
drh5240aeb2011-01-06 01:26:38 +0000329 while( i>0 && pData<=pLimit ){
drh100335b2011-01-05 21:20:52 +0000330 n = decodeVarint(a, &x);
331 a += n;
332 i -= n;
drh5240aeb2011-01-06 01:26:38 +0000333 nLocal -= n;
drh100335b2011-01-05 21:20:52 +0000334 zDesc[0] = sep;
335 sep = ',';
336 nDesc++;
337 zDesc++;
338 if( x==0 ){
drh5240aeb2011-01-06 01:26:38 +0000339 sprintf(zDesc, "*"); /* NULL is a "*" */
drh100335b2011-01-05 21:20:52 +0000340 }else if( x>=1 && x<=6 ){
341 v = (signed char)pData[0];
342 pData++;
343 switch( x ){
344 case 6: v = (v<<16) + (pData[0]<<8) + pData[1]; pData += 2;
345 case 5: v = (v<<16) + (pData[0]<<8) + pData[1]; pData += 2;
346 case 4: v = (v<<8) + pData[0]; pData++;
347 case 3: v = (v<<8) + pData[0]; pData++;
348 case 2: v = (v<<8) + pData[0]; pData++;
349 }
350 sprintf(zDesc, "%lld", v);
351 }else if( x==7 ){
352 sprintf(zDesc, "real");
353 pData += 8;
354 }else if( x==8 ){
355 sprintf(zDesc, "0");
356 }else if( x==9 ){
357 sprintf(zDesc, "1");
358 }else if( x>=12 ){
mistachkin0461cc42014-07-18 21:16:37 +0000359 i64 size = (x-12)/2;
drhb2c062d2011-01-05 21:46:52 +0000360 if( (x&1)==0 ){
mistachkin35683972014-07-19 15:30:01 +0000361 sprintf(zDesc, "blob(%lld)", size);
drh100335b2011-01-05 21:20:52 +0000362 }else{
mistachkin35683972014-07-19 15:30:01 +0000363 sprintf(zDesc, "txt(%lld)", size);
drh100335b2011-01-05 21:20:52 +0000364 }
365 pData += size;
366 }
mistachkinef607032014-07-19 15:40:39 +0000367 j = (int)strlen(zDesc);
drh100335b2011-01-05 21:20:52 +0000368 zDesc += j;
369 nDesc += j;
370 }
371 return nDesc;
372}
drh5240aeb2011-01-06 01:26:38 +0000373
374/*
375** Compute the local payload size given the total payload size and
376** the page size.
377*/
mistachkin0461cc42014-07-18 21:16:37 +0000378static i64 localPayload(i64 nPayload, char cType){
379 i64 maxLocal;
380 i64 minLocal;
381 i64 surplus;
382 i64 nLocal;
drh5240aeb2011-01-06 01:26:38 +0000383 if( cType==13 ){
384 /* Table leaf */
dan871f6e32015-08-03 17:03:31 +0000385 maxLocal = g.pagesize-35;
386 minLocal = (g.pagesize-12)*32/255-23;
drh5240aeb2011-01-06 01:26:38 +0000387 }else{
dan871f6e32015-08-03 17:03:31 +0000388 maxLocal = (g.pagesize-12)*64/255-23;
389 minLocal = (g.pagesize-12)*32/255-23;
drh5240aeb2011-01-06 01:26:38 +0000390 }
391 if( nPayload>maxLocal ){
dan871f6e32015-08-03 17:03:31 +0000392 surplus = minLocal + (nPayload-minLocal)%(g.pagesize-4);
drh5240aeb2011-01-06 01:26:38 +0000393 if( surplus<=maxLocal ){
394 nLocal = surplus;
395 }else{
396 nLocal = minLocal;
397 }
398 }else{
399 nLocal = nPayload;
400 }
401 return nLocal;
402}
drh100335b2011-01-05 21:20:52 +0000403
404
405/*
drh7ecc1472010-04-26 16:47:12 +0000406** Create a description for a single cell.
drh5240aeb2011-01-06 01:26:38 +0000407**
408** The return value is the local cell size.
drh7ecc1472010-04-26 16:47:12 +0000409*/
mistachkin0461cc42014-07-18 21:16:37 +0000410static i64 describeCell(
drh100335b2011-01-05 21:20:52 +0000411 unsigned char cType, /* Page type */
412 unsigned char *a, /* Cell content */
413 int showCellContent, /* Show cell content if true */
414 char **pzDesc /* Store description here */
415){
drh7ecc1472010-04-26 16:47:12 +0000416 int i;
mistachkin0461cc42014-07-18 21:16:37 +0000417 i64 nDesc = 0;
drh7ecc1472010-04-26 16:47:12 +0000418 int n = 0;
drh55550b72020-07-22 11:42:50 +0000419 u32 leftChild;
drh7ecc1472010-04-26 16:47:12 +0000420 i64 nPayload;
421 i64 rowid;
mistachkin0461cc42014-07-18 21:16:37 +0000422 i64 nLocal;
drh100335b2011-01-05 21:20:52 +0000423 static char zDesc[1000];
drh7ecc1472010-04-26 16:47:12 +0000424 i = 0;
425 if( cType<=5 ){
426 leftChild = ((a[0]*256 + a[1])*256 + a[2])*256 + a[3];
427 a += 4;
428 n += 4;
drh55550b72020-07-22 11:42:50 +0000429 sprintf(zDesc, "lx: %u ", leftChild);
drh7ecc1472010-04-26 16:47:12 +0000430 nDesc = strlen(zDesc);
431 }
432 if( cType!=5 ){
433 i = decodeVarint(a, &nPayload);
434 a += i;
435 n += i;
drh100335b2011-01-05 21:20:52 +0000436 sprintf(&zDesc[nDesc], "n: %lld ", nPayload);
drh7ecc1472010-04-26 16:47:12 +0000437 nDesc += strlen(&zDesc[nDesc]);
drh5240aeb2011-01-06 01:26:38 +0000438 nLocal = localPayload(nPayload, cType);
439 }else{
440 nPayload = nLocal = 0;
drh7ecc1472010-04-26 16:47:12 +0000441 }
442 if( cType==5 || cType==13 ){
443 i = decodeVarint(a, &rowid);
444 a += i;
445 n += i;
drh100335b2011-01-05 21:20:52 +0000446 sprintf(&zDesc[nDesc], "r: %lld ", rowid);
drh7ecc1472010-04-26 16:47:12 +0000447 nDesc += strlen(&zDesc[nDesc]);
448 }
drhb7787ee2011-01-06 15:51:18 +0000449 if( nLocal<nPayload ){
drh55550b72020-07-22 11:42:50 +0000450 u32 ovfl;
drhb7787ee2011-01-06 15:51:18 +0000451 unsigned char *b = &a[nLocal];
452 ovfl = ((b[0]*256 + b[1])*256 + b[2])*256 + b[3];
drh55550b72020-07-22 11:42:50 +0000453 sprintf(&zDesc[nDesc], "ov: %u ", ovfl);
drhb7787ee2011-01-06 15:51:18 +0000454 nDesc += strlen(&zDesc[nDesc]);
455 n += 4;
456 }
drh100335b2011-01-05 21:20:52 +0000457 if( showCellContent && cType!=5 ){
drh5240aeb2011-01-06 01:26:38 +0000458 nDesc += describeContent(a, nLocal, &zDesc[nDesc-1]);
drh100335b2011-01-05 21:20:52 +0000459 }
drh7ecc1472010-04-26 16:47:12 +0000460 *pzDesc = zDesc;
drh5240aeb2011-01-06 01:26:38 +0000461 return nLocal+n;
drh7ecc1472010-04-26 16:47:12 +0000462}
463
drh6a30cd52014-06-19 23:38:53 +0000464/* Print an offset followed by nByte bytes. Add extra white-space
465** at the end so that subsequent text is aligned.
466*/
467static void printBytes(
468 unsigned char *aData, /* Content being decoded */
469 unsigned char *aStart, /* Start of content to be printed */
470 int nByte /* Number of bytes to print */
471){
472 int j;
473 printf(" %03x: ", (int)(aStart-aData));
474 for(j=0; j<9; j++){
475 if( j>=nByte ){
476 printf(" ");
477 }else{
478 printf("%02x ", aStart[j]);
479 }
480 }
481}
482
483
484/*
485** Write a full decode on stdout for the cell at a[ofst].
486** Assume the page contains a header of size szPgHdr bytes.
487*/
488static void decodeCell(
489 unsigned char *a, /* Page content (without the page-1 header) */
490 unsigned pgno, /* Page number */
491 int iCell, /* Cell index */
492 int szPgHdr, /* Size of the page header. 0 or 100 */
493 int ofst /* Cell begins at a[ofst] */
494){
mistachkin44723ce2015-03-21 02:22:37 +0000495 int i, j = 0;
drh55550b72020-07-22 11:42:50 +0000496 u32 leftChild;
mistachkin0461cc42014-07-18 21:16:37 +0000497 i64 k;
drh6a30cd52014-06-19 23:38:53 +0000498 i64 nPayload;
499 i64 rowid;
500 i64 nHdr;
501 i64 iType;
mistachkin0461cc42014-07-18 21:16:37 +0000502 i64 nLocal;
drh6a30cd52014-06-19 23:38:53 +0000503 unsigned char *x = a + ofst;
504 unsigned char *end;
505 unsigned char cType = a[0];
drh419e0402014-06-20 01:32:42 +0000506 int nCol = 0;
507 int szCol[2000];
508 int ofstCol[2000];
509 int typeCol[2000];
drh6a30cd52014-06-19 23:38:53 +0000510
drh419e0402014-06-20 01:32:42 +0000511 printf("Cell[%d]:\n", iCell);
drh6a30cd52014-06-19 23:38:53 +0000512 if( cType<=5 ){
513 leftChild = ((x[0]*256 + x[1])*256 + x[2])*256 + x[3];
514 printBytes(a, x, 4);
drh55550b72020-07-22 11:42:50 +0000515 printf("left child page:: %u\n", leftChild);
drh6a30cd52014-06-19 23:38:53 +0000516 x += 4;
517 }
518 if( cType!=5 ){
519 i = decodeVarint(x, &nPayload);
520 printBytes(a, x, i);
521 nLocal = localPayload(nPayload, cType);
drh419e0402014-06-20 01:32:42 +0000522 if( nLocal==nPayload ){
mistachkin35683972014-07-19 15:30:01 +0000523 printf("payload-size: %lld\n", nPayload);
drh419e0402014-06-20 01:32:42 +0000524 }else{
mistachkin35683972014-07-19 15:30:01 +0000525 printf("payload-size: %lld (%lld local, %lld overflow)\n",
526 nPayload, nLocal, nPayload-nLocal);
drh419e0402014-06-20 01:32:42 +0000527 }
drh6a30cd52014-06-19 23:38:53 +0000528 x += i;
529 }else{
530 nPayload = nLocal = 0;
531 }
532 end = x + nLocal;
533 if( cType==5 || cType==13 ){
534 i = decodeVarint(x, &rowid);
535 printBytes(a, x, i);
536 printf("rowid: %lld\n", rowid);
537 x += i;
538 }
539 if( nLocal>0 ){
540 i = decodeVarint(x, &nHdr);
541 printBytes(a, x, i);
drh419e0402014-06-20 01:32:42 +0000542 printf("record-header-size: %d\n", (int)nHdr);
drh6a30cd52014-06-19 23:38:53 +0000543 j = i;
drh419e0402014-06-20 01:32:42 +0000544 nCol = 0;
545 k = nHdr;
drh970ea372017-03-16 13:14:03 +0000546 while( x+j<=end && j<nHdr ){
drh6a30cd52014-06-19 23:38:53 +0000547 const char *zTypeName;
548 int sz = 0;
549 char zNm[30];
550 i = decodeVarint(x+j, &iType);
551 printBytes(a, x+j, i);
drh419e0402014-06-20 01:32:42 +0000552 printf("typecode[%d]: %d - ", nCol, (int)iType);
drh6a30cd52014-06-19 23:38:53 +0000553 switch( iType ){
554 case 0: zTypeName = "NULL"; sz = 0; break;
555 case 1: zTypeName = "int8"; sz = 1; break;
556 case 2: zTypeName = "int16"; sz = 2; break;
557 case 3: zTypeName = "int24"; sz = 3; break;
558 case 4: zTypeName = "int32"; sz = 4; break;
559 case 5: zTypeName = "int48"; sz = 6; break;
560 case 6: zTypeName = "int64"; sz = 8; break;
561 case 7: zTypeName = "double"; sz = 8; break;
562 case 8: zTypeName = "zero"; sz = 0; break;
563 case 9: zTypeName = "one"; sz = 0; break;
564 case 10:
565 case 11: zTypeName = "error"; sz = 0; break;
566 default: {
567 sz = (int)(iType-12)/2;
568 sprintf(zNm, (iType&1)==0 ? "blob(%d)" : "text(%d)", sz);
569 zTypeName = zNm;
570 break;
571 }
572 }
573 printf("%s\n", zTypeName);
drh419e0402014-06-20 01:32:42 +0000574 szCol[nCol] = sz;
mistachkin0461cc42014-07-18 21:16:37 +0000575 ofstCol[nCol] = (int)k;
drh419e0402014-06-20 01:32:42 +0000576 typeCol[nCol] = (int)iType;
577 k += sz;
578 nCol++;
drh6a30cd52014-06-19 23:38:53 +0000579 j += i;
580 }
drh419e0402014-06-20 01:32:42 +0000581 for(i=0; i<nCol && ofstCol[i]+szCol[i]<=nLocal; i++){
582 int s = ofstCol[i];
583 i64 v;
584 const unsigned char *pData;
585 if( szCol[i]==0 ) continue;
586 printBytes(a, x+s, szCol[i]);
587 printf("data[%d]: ", i);
588 pData = x+s;
589 if( typeCol[i]<=7 ){
590 v = (signed char)pData[0];
591 for(k=1; k<szCol[i]; k++){
592 v = (v<<8) + pData[k];
593 }
594 if( typeCol[i]==7 ){
595 double r;
596 memcpy(&r, &v, sizeof(r));
597 printf("%#g\n", r);
598 }else{
599 printf("%lld\n", v);
600 }
601 }else{
drh56e67dd2014-06-20 13:55:06 +0000602 int ii, jj;
603 char zConst[32];
604 if( (typeCol[i]&1)==0 ){
605 zConst[0] = 'x';
606 zConst[1] = '\'';
607 for(ii=2, jj=0; jj<szCol[i] && ii<24; jj++, ii+=2){
608 sprintf(zConst+ii, "%02x", pData[jj]);
609 }
610 }else{
611 zConst[0] = '\'';
612 for(ii=1, jj=0; jj<szCol[i] && ii<24; jj++, ii++){
drhc56fac72015-10-29 13:48:15 +0000613 zConst[ii] = ISPRINT(pData[jj]) ? pData[jj] : '.';
drh56e67dd2014-06-20 13:55:06 +0000614 }
615 zConst[ii] = 0;
616 }
617 if( jj<szCol[i] ){
618 memcpy(zConst+ii, "...'", 5);
619 }else{
620 memcpy(zConst+ii, "'", 2);
621 }
622 printf("%s\n", zConst);
drh419e0402014-06-20 01:32:42 +0000623 }
624 j = ofstCol[i] + szCol[i];
625 }
drh6a30cd52014-06-19 23:38:53 +0000626 }
627 if( j<nLocal ){
628 printBytes(a, x+j, 0);
mistachkin35683972014-07-19 15:30:01 +0000629 printf("... %lld bytes of content ...\n", nLocal-j);
drh6a30cd52014-06-19 23:38:53 +0000630 }
631 if( nLocal<nPayload ){
632 printBytes(a, x+nLocal, 4);
drh55550b72020-07-22 11:42:50 +0000633 printf("overflow-page: %u\n", decodeInt32(x+nLocal));
drh6a30cd52014-06-19 23:38:53 +0000634 }
635}
636
637
drh7ecc1472010-04-26 16:47:12 +0000638/*
639** Decode a btree page
640*/
drh100335b2011-01-05 21:20:52 +0000641static void decode_btree_page(
642 unsigned char *a, /* Page content */
643 int pgno, /* Page number */
644 int hdrSize, /* Size of the page header. 0 or 100 */
645 char *zArgs /* Flags to control formatting */
646){
drh7ecc1472010-04-26 16:47:12 +0000647 const char *zType = "unknown";
648 int nCell;
drh5240aeb2011-01-06 01:26:38 +0000649 int i, j;
drh7ecc1472010-04-26 16:47:12 +0000650 int iCellPtr;
drh100335b2011-01-05 21:20:52 +0000651 int showCellContent = 0;
drh5240aeb2011-01-06 01:26:38 +0000652 int showMap = 0;
drh6a30cd52014-06-19 23:38:53 +0000653 int cellToDecode = -2;
drh5240aeb2011-01-06 01:26:38 +0000654 char *zMap = 0;
drh7ecc1472010-04-26 16:47:12 +0000655 switch( a[0] ){
656 case 2: zType = "index interior node"; break;
657 case 5: zType = "table interior node"; break;
658 case 10: zType = "index leaf"; break;
659 case 13: zType = "table leaf"; break;
660 }
drh100335b2011-01-05 21:20:52 +0000661 while( zArgs[0] ){
662 switch( zArgs[0] ){
663 case 'c': showCellContent = 1; break;
drh5240aeb2011-01-06 01:26:38 +0000664 case 'm': showMap = 1; break;
drh6a30cd52014-06-19 23:38:53 +0000665 case 'd': {
drhc56fac72015-10-29 13:48:15 +0000666 if( !ISDIGIT(zArgs[1]) ){
drh6a30cd52014-06-19 23:38:53 +0000667 cellToDecode = -1;
668 }else{
669 cellToDecode = 0;
drhc56fac72015-10-29 13:48:15 +0000670 while( ISDIGIT(zArgs[1]) ){
drh6a30cd52014-06-19 23:38:53 +0000671 zArgs++;
672 cellToDecode = cellToDecode*10 + zArgs[0] - '0';
673 }
674 }
675 break;
676 }
drh100335b2011-01-05 21:20:52 +0000677 }
678 zArgs++;
679 }
drh7ecc1472010-04-26 16:47:12 +0000680 nCell = a[3]*256 + a[4];
drh6a30cd52014-06-19 23:38:53 +0000681 iCellPtr = (a[0]==2 || a[0]==5) ? 12 : 8;
drh419e0402014-06-20 01:32:42 +0000682 if( cellToDecode>=nCell ){
drh6a30cd52014-06-19 23:38:53 +0000683 printf("Page %d has only %d cells\n", pgno, nCell);
684 return;
drh5240aeb2011-01-06 01:26:38 +0000685 }
drh419e0402014-06-20 01:32:42 +0000686 printf("Header on btree page %d:\n", pgno);
687 print_decode_line(a, 0, 1, zType);
688 print_decode_line(a, 1, 2, "Offset to first freeblock");
689 print_decode_line(a, 3, 2, "Number of cells on this page");
690 print_decode_line(a, 5, 2, "Offset to cell content area");
691 print_decode_line(a, 7, 1, "Fragmented byte count");
692 if( a[0]==2 || a[0]==5 ){
693 print_decode_line(a, 8, 4, "Right child");
694 }
695 if( cellToDecode==(-2) && nCell>0 ){
696 printf(" key: lx=left-child n=payload-size r=rowid\n");
697 }
drh5240aeb2011-01-06 01:26:38 +0000698 if( showMap ){
dan871f6e32015-08-03 17:03:31 +0000699 zMap = sqlite3_malloc(g.pagesize);
700 memset(zMap, '.', g.pagesize);
drh5240aeb2011-01-06 01:26:38 +0000701 memset(zMap, '1', hdrSize);
702 memset(&zMap[hdrSize], 'H', iCellPtr);
703 memset(&zMap[hdrSize+iCellPtr], 'P', 2*nCell);
704 }
drh7ecc1472010-04-26 16:47:12 +0000705 for(i=0; i<nCell; i++){
706 int cofst = iCellPtr + i*2;
707 char *zDesc;
mistachkin0461cc42014-07-18 21:16:37 +0000708 i64 n;
drh5240aeb2011-01-06 01:26:38 +0000709
drh7ecc1472010-04-26 16:47:12 +0000710 cofst = a[cofst]*256 + a[cofst+1];
drh5240aeb2011-01-06 01:26:38 +0000711 n = describeCell(a[0], &a[cofst-hdrSize], showCellContent, &zDesc);
712 if( showMap ){
713 char zBuf[30];
mistachkin0461cc42014-07-18 21:16:37 +0000714 memset(&zMap[cofst], '*', (size_t)n);
drh5240aeb2011-01-06 01:26:38 +0000715 zMap[cofst] = '[';
716 zMap[cofst+n-1] = ']';
717 sprintf(zBuf, "%d", i);
mistachkinef607032014-07-19 15:40:39 +0000718 j = (int)strlen(zBuf);
drh5240aeb2011-01-06 01:26:38 +0000719 if( j<=n-2 ) memcpy(&zMap[cofst+1], zBuf, j);
720 }
drh6a30cd52014-06-19 23:38:53 +0000721 if( cellToDecode==(-2) ){
722 printf(" %03x: cell[%d] %s\n", cofst, i, zDesc);
723 }else if( cellToDecode==(-1) || cellToDecode==i ){
724 decodeCell(a, pgno, i, hdrSize, cofst-hdrSize);
725 }
drh7ecc1472010-04-26 16:47:12 +0000726 }
drh5240aeb2011-01-06 01:26:38 +0000727 if( showMap ){
drh419e0402014-06-20 01:32:42 +0000728 printf("Page map: (H=header P=cell-index 1=page-1-header .=free-space)\n");
mistachkin2b5fbb22021-12-31 18:26:50 +0000729 for(i=0; (u32)i<g.pagesize; i+=64){
drh5240aeb2011-01-06 01:26:38 +0000730 printf(" %03x: %.64s\n", i, &zMap[i]);
731 }
dan871f6e32015-08-03 17:03:31 +0000732 sqlite3_free(zMap);
drh6a30cd52014-06-19 23:38:53 +0000733 }
drh7ecc1472010-04-26 16:47:12 +0000734}
735
drh7d105f82010-08-23 15:26:49 +0000736/*
737** Decode a freelist trunk page.
738*/
739static void decode_trunk_page(
drh55550b72020-07-22 11:42:50 +0000740 u32 pgno, /* The page number */
drh7d105f82010-08-23 15:26:49 +0000741 int detail, /* Show leaf pages if true */
742 int recursive /* Follow the trunk change if true */
743){
drh55550b72020-07-22 11:42:50 +0000744 u32 i;
745 u32 n;
drh7d105f82010-08-23 15:26:49 +0000746 unsigned char *a;
747 while( pgno>0 ){
dan871f6e32015-08-03 17:03:31 +0000748 a = fileRead((pgno-1)*g.pagesize, g.pagesize);
drh7d105f82010-08-23 15:26:49 +0000749 printf("Decode of freelist trunk page %d:\n", pgno);
750 print_decode_line(a, 0, 4, "Next freelist trunk page");
751 print_decode_line(a, 4, 4, "Number of entries on this page");
752 if( detail ){
drh55550b72020-07-22 11:42:50 +0000753 n = decodeInt32(&a[4]);
754 for(i=0; i<n && i<g.pagesize/4; i++){
755 u32 x = decodeInt32(&a[8+4*i]);
larrybrd95a6522021-06-16 13:26:40 +0000756 char zIdx[13];
drh7d105f82010-08-23 15:26:49 +0000757 sprintf(zIdx, "[%d]", i);
758 printf(" %5s %7u", zIdx, x);
759 if( i%5==4 ) printf("\n");
760 }
761 if( i%5!=0 ) printf("\n");
762 }
763 if( !recursive ){
764 pgno = 0;
765 }else{
drh55550b72020-07-22 11:42:50 +0000766 pgno = decodeInt32(&a[0]);
drh7d105f82010-08-23 15:26:49 +0000767 }
dan871f6e32015-08-03 17:03:31 +0000768 sqlite3_free(a);
drh7d105f82010-08-23 15:26:49 +0000769 }
770}
771
772/*
drh3aeea462012-04-03 14:59:50 +0000773** A short text comment on the use of each page.
774*/
775static char **zPageUse;
776
777/*
778** Add a comment on the use of a page.
779*/
drh55550b72020-07-22 11:42:50 +0000780static void page_usage_msg(u32 pgno, const char *zFormat, ...){
drh3aeea462012-04-03 14:59:50 +0000781 va_list ap;
782 char *zMsg;
783
784 va_start(ap, zFormat);
785 zMsg = sqlite3_vmprintf(zFormat, ap);
786 va_end(ap);
dan871f6e32015-08-03 17:03:31 +0000787 if( pgno<=0 || pgno>g.mxPage ){
drh55550b72020-07-22 11:42:50 +0000788 printf("ERROR: page %d out of range 1..%u: %s\n",
dan871f6e32015-08-03 17:03:31 +0000789 pgno, g.mxPage, zMsg);
drh3aeea462012-04-03 14:59:50 +0000790 sqlite3_free(zMsg);
791 return;
792 }
793 if( zPageUse[pgno]!=0 ){
794 printf("ERROR: page %d used multiple times:\n", pgno);
795 printf("ERROR: previous: %s\n", zPageUse[pgno]);
drh103a70f2013-02-19 20:25:16 +0000796 printf("ERROR: current: %s\n", zMsg);
drh3aeea462012-04-03 14:59:50 +0000797 sqlite3_free(zPageUse[pgno]);
798 }
799 zPageUse[pgno] = zMsg;
800}
801
802/*
803** Find overflow pages of a cell and describe their usage.
804*/
805static void page_usage_cell(
806 unsigned char cType, /* Page type */
807 unsigned char *a, /* Cell content */
drh55550b72020-07-22 11:42:50 +0000808 u32 pgno, /* page containing the cell */
drh3aeea462012-04-03 14:59:50 +0000809 int cellno /* Index of the cell on the page */
810){
811 int i;
drh3aeea462012-04-03 14:59:50 +0000812 int n = 0;
813 i64 nPayload;
814 i64 rowid;
mistachkin0461cc42014-07-18 21:16:37 +0000815 i64 nLocal;
drh3aeea462012-04-03 14:59:50 +0000816 i = 0;
817 if( cType<=5 ){
818 a += 4;
819 n += 4;
820 }
821 if( cType!=5 ){
822 i = decodeVarint(a, &nPayload);
823 a += i;
824 n += i;
825 nLocal = localPayload(nPayload, cType);
826 }else{
827 nPayload = nLocal = 0;
828 }
829 if( cType==5 || cType==13 ){
830 i = decodeVarint(a, &rowid);
831 a += i;
832 n += i;
833 }
834 if( nLocal<nPayload ){
drh55550b72020-07-22 11:42:50 +0000835 u32 ovfl = decodeInt32(a+nLocal);
836 u32 cnt = 0;
dan871f6e32015-08-03 17:03:31 +0000837 while( ovfl && (cnt++)<g.mxPage ){
drh55550b72020-07-22 11:42:50 +0000838 page_usage_msg(ovfl, "overflow %d from cell %d of page %u",
drh3aeea462012-04-03 14:59:50 +0000839 cnt, cellno, pgno);
drhaaad6962019-03-05 23:49:17 +0000840 a = fileRead((ovfl-1)*(sqlite3_int64)g.pagesize, 4);
drh3aeea462012-04-03 14:59:50 +0000841 ovfl = decodeInt32(a);
dan871f6e32015-08-03 17:03:31 +0000842 sqlite3_free(a);
drh3aeea462012-04-03 14:59:50 +0000843 }
844 }
845}
846
drh8083ef02019-04-17 12:29:45 +0000847/*
848** True if the memory is all zeros
849*/
850static int allZero(unsigned char *a, int n){
851 while( n && (a++)[0]==0 ){ n--; }
852 return n==0;
853}
854
drh3aeea462012-04-03 14:59:50 +0000855
856/*
drh8083ef02019-04-17 12:29:45 +0000857** Describe the usages of a b-tree page.
858**
859** If parent==0, then this is the root of a btree. If parent<0 then
860** this is an orphan page.
drh3aeea462012-04-03 14:59:50 +0000861*/
862static void page_usage_btree(
drh55550b72020-07-22 11:42:50 +0000863 u32 pgno, /* Page to describe */
mistachkin2b5fbb22021-12-31 18:26:50 +0000864 int parent, /* Parent of this page. 0 for root pages */
drh3aeea462012-04-03 14:59:50 +0000865 int idx, /* Which child of the parent */
866 const char *zName /* Name of the table */
867){
868 unsigned char *a;
869 const char *zType = "corrupt node";
870 int nCell;
871 int i;
872 int hdr = pgno==1 ? 100 : 0;
drh25f933a2019-04-17 13:23:28 +0000873 char zEntry[30];
drh3aeea462012-04-03 14:59:50 +0000874
dan871f6e32015-08-03 17:03:31 +0000875 if( pgno<=0 || pgno>g.mxPage ) return;
876 a = fileRead((pgno-1)*g.pagesize, g.pagesize);
drh3aeea462012-04-03 14:59:50 +0000877 switch( a[hdr] ){
drh8083ef02019-04-17 12:29:45 +0000878 case 0: {
879 if( allZero(a, g.pagesize) ){
880 zType = "zeroed page";
881 }else if( parent<0 ){
882 return;
883 }else{
884 zType = "corrupt node";
885 }
886 break;
887 }
drh3aeea462012-04-03 14:59:50 +0000888 case 2: zType = "interior node of index"; break;
889 case 5: zType = "interior node of table"; break;
890 case 10: zType = "leaf of index"; break;
891 case 13: zType = "leaf of table"; break;
drh8083ef02019-04-17 12:29:45 +0000892 default: {
893 if( parent<0 ) return;
894 zType = "corrupt node";
895 }
drh3aeea462012-04-03 14:59:50 +0000896 }
drh3aeea462012-04-03 14:59:50 +0000897 nCell = a[hdr+3]*256 + a[hdr+4];
drh25f933a2019-04-17 13:23:28 +0000898 if( nCell==1 ){
899 sqlite3_snprintf(sizeof(zEntry),zEntry,"1 row");
900 }else{
901 sqlite3_snprintf(sizeof(zEntry),zEntry,"%d rows", nCell);
902 }
903 if( parent>0 ){
904 page_usage_msg(pgno, "%s [%s], child %d of page %d, %s",
905 zType, zName, idx, parent, zEntry);
906 }else if( parent==0 ){
907 page_usage_msg(pgno, "root %s [%s], %s", zType, zName, zEntry);
908 }else{
909 page_usage_msg(pgno, "orphaned %s, %s", zType, zEntry);
910 }
drh3aeea462012-04-03 14:59:50 +0000911 if( a[hdr]==2 || a[hdr]==5 ){
912 int cellstart = hdr+12;
drh55550b72020-07-22 11:42:50 +0000913 u32 child;
drh3aeea462012-04-03 14:59:50 +0000914 for(i=0; i<nCell; i++){
drh19a7f722021-04-26 23:57:02 +0000915 u32 cellidx;
drh55550b72020-07-22 11:42:50 +0000916 u32 ofst;
drh3aeea462012-04-03 14:59:50 +0000917
drh19a7f722021-04-26 23:57:02 +0000918 cellidx = cellstart + i*2;
919 if( cellidx+1 >= g.pagesize ){
drh2f40dc92021-04-27 00:05:03 +0000920 printf("ERROR: page %d too many cells (%d)\n", pgno, nCell);
drh19a7f722021-04-26 23:57:02 +0000921 break;
922 }
923 ofst = a[cellidx]*256 + a[cellidx+1];
924 if( ofst<cellidx+2 || ofst+4>=g.pagesize ){
drh2f40dc92021-04-27 00:05:03 +0000925 printf("ERROR: page %d cell %d out of bounds\n", pgno, i);
drh19a7f722021-04-26 23:57:02 +0000926 continue;
927 }
drh3aeea462012-04-03 14:59:50 +0000928 child = decodeInt32(a+ofst);
929 page_usage_btree(child, pgno, i, zName);
930 }
931 child = decodeInt32(a+cellstart-4);
932 page_usage_btree(child, pgno, i, zName);
933 }
934 if( a[hdr]==2 || a[hdr]==10 || a[hdr]==13 ){
935 int cellstart = hdr + 8 + 4*(a[hdr]<=5);
936 for(i=0; i<nCell; i++){
937 int ofst;
938 ofst = cellstart + i*2;
939 ofst = a[ofst]*256 + a[ofst+1];
940 page_usage_cell(a[hdr], a+ofst, pgno, i);
941 }
942 }
dan871f6e32015-08-03 17:03:31 +0000943 sqlite3_free(a);
drh3aeea462012-04-03 14:59:50 +0000944}
945
946/*
947** Determine page usage by the freelist
948*/
drh55550b72020-07-22 11:42:50 +0000949static void page_usage_freelist(u32 pgno){
drh3aeea462012-04-03 14:59:50 +0000950 unsigned char *a;
951 int cnt = 0;
952 int i;
953 int n;
954 int iNext;
955 int parent = 1;
956
mistachkin2b5fbb22021-12-31 18:26:50 +0000957 while( pgno>0 && pgno<=g.mxPage && (u32)(cnt++)<g.mxPage ){
drh3aeea462012-04-03 14:59:50 +0000958 page_usage_msg(pgno, "freelist trunk #%d child of %d", cnt, parent);
dan871f6e32015-08-03 17:03:31 +0000959 a = fileRead((pgno-1)*g.pagesize, g.pagesize);
drh3aeea462012-04-03 14:59:50 +0000960 iNext = decodeInt32(a);
961 n = decodeInt32(a+4);
962 for(i=0; i<n; i++){
963 int child = decodeInt32(a + (i*4+8));
964 page_usage_msg(child, "freelist leaf, child %d of trunk page %d",
965 i, pgno);
966 }
dan871f6e32015-08-03 17:03:31 +0000967 sqlite3_free(a);
drh3aeea462012-04-03 14:59:50 +0000968 parent = pgno;
969 pgno = iNext;
970 }
971}
972
973/*
drh344a97b2013-02-19 22:26:51 +0000974** Determine pages used as PTRMAP pages
975*/
drh55550b72020-07-22 11:42:50 +0000976static void page_usage_ptrmap(u8 *a){
drhc1f73e22020-01-14 13:24:14 +0000977 if( decodeInt32(a+52) ){
dan871f6e32015-08-03 17:03:31 +0000978 int usable = g.pagesize - a[20];
drh55550b72020-07-22 11:42:50 +0000979 u64 pgno = 2;
drh344a97b2013-02-19 22:26:51 +0000980 int perPage = usable/5;
dan871f6e32015-08-03 17:03:31 +0000981 while( pgno<=g.mxPage ){
drh55550b72020-07-22 11:42:50 +0000982 page_usage_msg((u32)pgno, "PTRMAP page covering %llu..%llu",
drh344a97b2013-02-19 22:26:51 +0000983 pgno+1, pgno+perPage);
984 pgno += perPage + 1;
985 }
986 }
987}
988
989/*
drh3aeea462012-04-03 14:59:50 +0000990** Try to figure out how every page in the database file is being used.
991*/
dan871f6e32015-08-03 17:03:31 +0000992static void page_usage_report(const char *zPrg, const char *zDbName){
drh55550b72020-07-22 11:42:50 +0000993 u32 i, j;
drh3aeea462012-04-03 14:59:50 +0000994 int rc;
995 sqlite3 *db;
996 sqlite3_stmt *pStmt;
997 unsigned char *a;
drh00e637f2013-02-19 18:45:11 +0000998 char zQuery[200];
drh3aeea462012-04-03 14:59:50 +0000999
1000 /* Avoid the pathological case */
dan871f6e32015-08-03 17:03:31 +00001001 if( g.mxPage<1 ){
drh3aeea462012-04-03 14:59:50 +00001002 printf("empty database\n");
1003 return;
1004 }
1005
1006 /* Open the database file */
dan871f6e32015-08-03 17:03:31 +00001007 db = openDatabase(zPrg, zDbName);
drh3aeea462012-04-03 14:59:50 +00001008
dan871f6e32015-08-03 17:03:31 +00001009 /* Set up global variables zPageUse[] and g.mxPage to record page
drh3aeea462012-04-03 14:59:50 +00001010 ** usages */
drh55550b72020-07-22 11:42:50 +00001011 zPageUse = sqlite3_malloc64( sizeof(zPageUse[0])*(g.mxPage+1) );
drh3aeea462012-04-03 14:59:50 +00001012 if( zPageUse==0 ) out_of_memory();
dan871f6e32015-08-03 17:03:31 +00001013 memset(zPageUse, 0, sizeof(zPageUse[0])*(g.mxPage+1));
drh3aeea462012-04-03 14:59:50 +00001014
1015 /* Discover the usage of each page */
dan871f6e32015-08-03 17:03:31 +00001016 a = fileRead(0, 100);
drh3aeea462012-04-03 14:59:50 +00001017 page_usage_freelist(decodeInt32(a+32));
drh344a97b2013-02-19 22:26:51 +00001018 page_usage_ptrmap(a);
dan871f6e32015-08-03 17:03:31 +00001019 sqlite3_free(a);
drh067b92b2020-06-19 15:24:12 +00001020 page_usage_btree(1, 0, 0, "sqlite_schema");
drh00e637f2013-02-19 18:45:11 +00001021 sqlite3_exec(db, "PRAGMA writable_schema=ON", 0, 0, 0);
1022 for(j=0; j<2; j++){
1023 sqlite3_snprintf(sizeof(zQuery), zQuery,
1024 "SELECT type, name, rootpage FROM SQLITE_MASTER WHERE rootpage"
1025 " ORDER BY rowid %s", j?"DESC":"");
1026 rc = sqlite3_prepare_v2(db, zQuery, -1, &pStmt, 0);
1027 if( rc==SQLITE_OK ){
1028 while( sqlite3_step(pStmt)==SQLITE_ROW ){
drh55550b72020-07-22 11:42:50 +00001029 u32 pgno = (u32)sqlite3_column_int64(pStmt, 2);
drhdb718d82014-01-28 20:36:22 +00001030 page_usage_btree(pgno, 0, 0, (const char*)sqlite3_column_text(pStmt,1));
drh00e637f2013-02-19 18:45:11 +00001031 }
1032 }else{
1033 printf("ERROR: cannot query database: %s\n", sqlite3_errmsg(db));
drh3aeea462012-04-03 14:59:50 +00001034 }
drh00e637f2013-02-19 18:45:11 +00001035 rc = sqlite3_finalize(pStmt);
1036 if( rc==SQLITE_OK ) break;
drh3aeea462012-04-03 14:59:50 +00001037 }
drh3aeea462012-04-03 14:59:50 +00001038 sqlite3_close(db);
1039
1040 /* Print the report and free memory used */
dan871f6e32015-08-03 17:03:31 +00001041 for(i=1; i<=g.mxPage; i++){
drh8083ef02019-04-17 12:29:45 +00001042 if( zPageUse[i]==0 ) page_usage_btree(i, -1, 0, 0);
drh55550b72020-07-22 11:42:50 +00001043 printf("%5u: %s\n", i, zPageUse[i] ? zPageUse[i] : "???");
drh26ec5682021-06-08 17:56:16 +00001044 }
1045 for(i=1; i<=g.mxPage; i++){
drh3aeea462012-04-03 14:59:50 +00001046 sqlite3_free(zPageUse[i]);
1047 }
1048 sqlite3_free(zPageUse);
1049 zPageUse = 0;
1050}
1051
1052/*
drh344a97b2013-02-19 22:26:51 +00001053** Try to figure out how every page in the database file is being used.
1054*/
1055static void ptrmap_coverage_report(const char *zDbName){
drh55550b72020-07-22 11:42:50 +00001056 u64 pgno;
drh344a97b2013-02-19 22:26:51 +00001057 unsigned char *aHdr;
1058 unsigned char *a;
1059 int usable;
1060 int perPage;
mistachkin0461cc42014-07-18 21:16:37 +00001061 int i;
drh344a97b2013-02-19 22:26:51 +00001062
1063 /* Avoid the pathological case */
dan871f6e32015-08-03 17:03:31 +00001064 if( g.mxPage<1 ){
drh344a97b2013-02-19 22:26:51 +00001065 printf("empty database\n");
1066 return;
1067 }
1068
1069 /* Make sure PTRMAPs are used in this database */
dan871f6e32015-08-03 17:03:31 +00001070 aHdr = fileRead(0, 100);
drh344a97b2013-02-19 22:26:51 +00001071 if( aHdr[55]==0 ){
1072 printf("database does not use PTRMAP pages\n");
1073 return;
1074 }
dan871f6e32015-08-03 17:03:31 +00001075 usable = g.pagesize - aHdr[20];
drh344a97b2013-02-19 22:26:51 +00001076 perPage = usable/5;
dan871f6e32015-08-03 17:03:31 +00001077 sqlite3_free(aHdr);
drh067b92b2020-06-19 15:24:12 +00001078 printf("%5d: root of sqlite_schema\n", 1);
dan871f6e32015-08-03 17:03:31 +00001079 for(pgno=2; pgno<=g.mxPage; pgno += perPage+1){
drh55550b72020-07-22 11:42:50 +00001080 printf("%5llu: PTRMAP page covering %llu..%llu\n", pgno,
drh344a97b2013-02-19 22:26:51 +00001081 pgno+1, pgno+perPage);
dan871f6e32015-08-03 17:03:31 +00001082 a = fileRead((pgno-1)*g.pagesize, usable);
1083 for(i=0; i+5<=usable && pgno+1+i/5<=g.mxPage; i+=5){
drh344a97b2013-02-19 22:26:51 +00001084 const char *zType = "???";
drh55550b72020-07-22 11:42:50 +00001085 u32 iFrom = decodeInt32(&a[i+1]);
drh344a97b2013-02-19 22:26:51 +00001086 switch( a[i] ){
1087 case 1: zType = "b-tree root page"; break;
1088 case 2: zType = "freelist page"; break;
1089 case 3: zType = "first page of overflow"; break;
1090 case 4: zType = "later page of overflow"; break;
1091 case 5: zType = "b-tree non-root page"; break;
1092 }
drh55550b72020-07-22 11:42:50 +00001093 printf("%5llu: %s, parent=%u\n", pgno+1+i/5, zType, iFrom);
drh344a97b2013-02-19 22:26:51 +00001094 }
dan871f6e32015-08-03 17:03:31 +00001095 sqlite3_free(a);
drh344a97b2013-02-19 22:26:51 +00001096 }
1097}
1098
1099/*
drh7d105f82010-08-23 15:26:49 +00001100** Print a usage comment
1101*/
1102static void usage(const char *argv0){
dan871f6e32015-08-03 17:03:31 +00001103 fprintf(stderr, "Usage %s ?--uri? FILENAME ?args...?\n\n", argv0);
drh7d105f82010-08-23 15:26:49 +00001104 fprintf(stderr,
dan871f6e32015-08-03 17:03:31 +00001105 "switches:\n"
dan8fb1bd22015-08-04 15:23:49 +00001106 " --raw Read db file directly, bypassing SQLite VFS\n"
drh7d105f82010-08-23 15:26:49 +00001107 "args:\n"
1108 " dbheader Show database header\n"
drh3aeea462012-04-03 14:59:50 +00001109 " pgidx Index of how each page is used\n"
drh344a97b2013-02-19 22:26:51 +00001110 " ptrmap Show all PTRMAP page content\n"
drh7d105f82010-08-23 15:26:49 +00001111 " NNN..MMM Show hex of pages NNN through MMM\n"
1112 " NNN..end Show hex of pages NNN through end of file\n"
1113 " NNNb Decode btree page NNN\n"
drh5240aeb2011-01-06 01:26:38 +00001114 " NNNbc Decode btree page NNN and show content\n"
1115 " NNNbm Decode btree page NNN and show a layout map\n"
drh6a30cd52014-06-19 23:38:53 +00001116 " NNNbdCCC Decode cell CCC on btree page NNN\n"
drh7d105f82010-08-23 15:26:49 +00001117 " NNNt Decode freelist trunk page NNN\n"
drh47fb0002011-04-13 16:52:41 +00001118 " NNNtd Show leaf freelist pages on the decode\n"
dan53d89cd2014-08-20 10:42:16 +00001119 " NNNtr Recursively decode freelist starting at NNN\n"
drh7d105f82010-08-23 15:26:49 +00001120 );
1121}
1122
drh0de8c112002-07-06 16:32:14 +00001123int main(int argc, char **argv){
dan871f6e32015-08-03 17:03:31 +00001124 sqlite3_int64 szFile;
1125 unsigned char *zPgSz;
1126 const char *zPrg = argv[0]; /* Name of this executable */
1127 char **azArg = argv;
1128 int nArg = argc;
1129
1130 /* Check for the "--uri" or "-uri" switch. */
1131 if( nArg>1 ){
dan8fb1bd22015-08-04 15:23:49 +00001132 if( sqlite3_stricmp("-raw", azArg[1])==0
1133 || sqlite3_stricmp("--raw", azArg[1])==0
dan871f6e32015-08-03 17:03:31 +00001134 ){
dan8fb1bd22015-08-04 15:23:49 +00001135 g.bRaw = 1;
dan871f6e32015-08-03 17:03:31 +00001136 azArg++;
1137 nArg--;
1138 }
1139 }
1140
1141 if( nArg<2 ){
1142 usage(zPrg);
drh0de8c112002-07-06 16:32:14 +00001143 exit(1);
1144 }
dan871f6e32015-08-03 17:03:31 +00001145
dan8fb1bd22015-08-04 15:23:49 +00001146 fileOpen(zPrg, azArg[1]);
dan871f6e32015-08-03 17:03:31 +00001147 szFile = fileGetsize();
1148
1149 zPgSz = fileRead(16, 2);
1150 g.pagesize = zPgSz[0]*256 + zPgSz[1]*65536;
1151 if( g.pagesize==0 ) g.pagesize = 1024;
1152 sqlite3_free(zPgSz);
1153
1154 printf("Pagesize: %d\n", g.pagesize);
drh55550b72020-07-22 11:42:50 +00001155 g.mxPage = (u32)((szFile+g.pagesize-1)/g.pagesize);
dan871f6e32015-08-03 17:03:31 +00001156
drh55550b72020-07-22 11:42:50 +00001157 printf("Available pages: 1..%u\n", g.mxPage);
dan871f6e32015-08-03 17:03:31 +00001158 if( nArg==2 ){
drh55550b72020-07-22 11:42:50 +00001159 u32 i;
dan871f6e32015-08-03 17:03:31 +00001160 for(i=1; i<=g.mxPage; i++) print_page(i);
drh0de8c112002-07-06 16:32:14 +00001161 }else{
1162 int i;
dan871f6e32015-08-03 17:03:31 +00001163 for(i=2; i<nArg; i++){
drh55550b72020-07-22 11:42:50 +00001164 u32 iStart, iEnd;
drh0de8c112002-07-06 16:32:14 +00001165 char *zLeft;
dan871f6e32015-08-03 17:03:31 +00001166 if( strcmp(azArg[i], "dbheader")==0 ){
drh562cedb2010-04-26 15:44:07 +00001167 print_db_header();
1168 continue;
1169 }
dan871f6e32015-08-03 17:03:31 +00001170 if( strcmp(azArg[i], "pgidx")==0 ){
1171 page_usage_report(zPrg, azArg[1]);
drh3aeea462012-04-03 14:59:50 +00001172 continue;
1173 }
dan871f6e32015-08-03 17:03:31 +00001174 if( strcmp(azArg[i], "ptrmap")==0 ){
1175 ptrmap_coverage_report(azArg[1]);
drh344a97b2013-02-19 22:26:51 +00001176 continue;
1177 }
dan871f6e32015-08-03 17:03:31 +00001178 if( strcmp(azArg[i], "help")==0 ){
dan8fb1bd22015-08-04 15:23:49 +00001179 usage(zPrg);
drh344a97b2013-02-19 22:26:51 +00001180 continue;
1181 }
drhc56fac72015-10-29 13:48:15 +00001182 if( !ISDIGIT(azArg[i][0]) ){
dan8fb1bd22015-08-04 15:23:49 +00001183 fprintf(stderr, "%s: unknown option: [%s]\n", zPrg, azArg[i]);
drh562cedb2010-04-26 15:44:07 +00001184 continue;
1185 }
drh55550b72020-07-22 11:42:50 +00001186 iStart = strtoul(azArg[i], &zLeft, 0);
drh0de8c112002-07-06 16:32:14 +00001187 if( zLeft && strcmp(zLeft,"..end")==0 ){
dan871f6e32015-08-03 17:03:31 +00001188 iEnd = g.mxPage;
drh0de8c112002-07-06 16:32:14 +00001189 }else if( zLeft && zLeft[0]=='.' && zLeft[1]=='.' ){
1190 iEnd = strtol(&zLeft[2], 0, 0);
drh7ecc1472010-04-26 16:47:12 +00001191 }else if( zLeft && zLeft[0]=='b' ){
1192 int ofst, nByte, hdrSize;
1193 unsigned char *a;
1194 if( iStart==1 ){
1195 ofst = hdrSize = 100;
dan871f6e32015-08-03 17:03:31 +00001196 nByte = g.pagesize-100;
drh7ecc1472010-04-26 16:47:12 +00001197 }else{
1198 hdrSize = 0;
dan871f6e32015-08-03 17:03:31 +00001199 ofst = (iStart-1)*g.pagesize;
1200 nByte = g.pagesize;
drh7ecc1472010-04-26 16:47:12 +00001201 }
dan871f6e32015-08-03 17:03:31 +00001202 a = fileRead(ofst, nByte);
drh100335b2011-01-05 21:20:52 +00001203 decode_btree_page(a, iStart, hdrSize, &zLeft[1]);
dan871f6e32015-08-03 17:03:31 +00001204 sqlite3_free(a);
drh7ecc1472010-04-26 16:47:12 +00001205 continue;
drh7d105f82010-08-23 15:26:49 +00001206 }else if( zLeft && zLeft[0]=='t' ){
drh7d105f82010-08-23 15:26:49 +00001207 int detail = 0;
1208 int recursive = 0;
mistachkin8ccdef62015-12-16 22:06:52 +00001209 int j;
1210 for(j=1; zLeft[j]; j++){
1211 if( zLeft[j]=='r' ) recursive = 1;
1212 if( zLeft[j]=='d' ) detail = 1;
drh7d105f82010-08-23 15:26:49 +00001213 }
dan871f6e32015-08-03 17:03:31 +00001214 decode_trunk_page(iStart, detail, recursive);
drh7d105f82010-08-23 15:26:49 +00001215 continue;
drh0de8c112002-07-06 16:32:14 +00001216 }else{
1217 iEnd = iStart;
1218 }
dan871f6e32015-08-03 17:03:31 +00001219 if( iStart<1 || iEnd<iStart || iEnd>g.mxPage ){
drh0de8c112002-07-06 16:32:14 +00001220 fprintf(stderr,
1221 "Page argument should be LOWER?..UPPER?. Range 1 to %d\n",
dan871f6e32015-08-03 17:03:31 +00001222 g.mxPage);
drh0de8c112002-07-06 16:32:14 +00001223 exit(1);
1224 }
1225 while( iStart<=iEnd ){
1226 print_page(iStart);
1227 iStart++;
1228 }
1229 }
1230 }
dan871f6e32015-08-03 17:03:31 +00001231 fileClose();
drhdb718d82014-01-28 20:36:22 +00001232 return 0;
drh0de8c112002-07-06 16:32:14 +00001233}