2 ** This program searches an SQLite database file for the lengths and
3 ** offsets for all TEXT or BLOB entries for a particular column of a
4 ** particular table. The rowid, size and offset for the column are
5 ** written to standard output. There are three arguments, which are the
6 ** name of the database file, the table, and the column.
14 typedef unsigned char u8
;
15 typedef struct GState GState
;
17 #define ArraySize(X) (sizeof(X)/sizeof(X[0]))
20 ** Global state information for this program.
23 char *zErr
; /* Error message text */
24 FILE *f
; /* Open database file */
25 int szPg
; /* Page size for the database file */
26 int iRoot
; /* Root page of the table */
27 int iCol
; /* Column number for the column */
28 int pgno
; /* Current page number */
29 u8
*aPage
; /* Current page content */
30 u8
*aStack
[20]; /* Page stack */
31 int aPgno
[20]; /* Page number stack */
32 int nStack
; /* Depth of stack */
33 int bTrace
; /* True for tracing output */
39 static void ofstError(GState
*p
, const char *zFormat
, ...){
41 sqlite3_free(p
->zErr
);
42 va_start(ap
, zFormat
);
43 p
->zErr
= sqlite3_vmprintf(zFormat
, ap
);
48 ** Write a trace message
50 static void ofstTrace(GState
*p
, const char *zFormat
, ...){
53 va_start(ap
, zFormat
);
60 ** Find the root page of the table and the column number of the column.
62 static void ofstRootAndColumn(
63 GState
*p
, /* Global state */
64 const char *zFile
, /* Name of the database file */
65 const char *zTable
, /* Name of the table */
66 const char *zColumn
/* Name of the column */
69 sqlite3_stmt
*pStmt
= 0;
73 rc
= sqlite3_open(zFile
, &db
);
75 ofstError(p
, "cannot open database file \"%s\"", zFile
);
76 goto rootAndColumn_exit
;
78 zSql
= sqlite3_mprintf("SELECT rootpage FROM sqlite_schema WHERE name=%Q",
80 rc
= sqlite3_prepare_v2(db
, zSql
, -1, &pStmt
, 0);
81 if( rc
) ofstError(p
, "%s: [%s]", sqlite3_errmsg(db
), zSql
);
83 if( p
->zErr
) goto rootAndColumn_exit
;
84 if( sqlite3_step(pStmt
)!=SQLITE_ROW
){
85 ofstError(p
, "cannot find table [%s]\n", zTable
);
86 sqlite3_finalize(pStmt
);
87 goto rootAndColumn_exit
;
89 p
->iRoot
= sqlite3_column_int(pStmt
, 0);
90 sqlite3_finalize(pStmt
);
93 zSql
= sqlite3_mprintf("PRAGMA table_info(%Q)", zTable
);
94 rc
= sqlite3_prepare_v2(db
, zSql
, -1, &pStmt
, 0);
95 if( rc
) ofstError(p
, "%s: [%s}", sqlite3_errmsg(db
), zSql
);
97 if( p
->zErr
) goto rootAndColumn_exit
;
98 while( sqlite3_step(pStmt
)==SQLITE_ROW
){
99 const char *zCol
= sqlite3_column_text(pStmt
, 1);
100 if( strlen(zCol
)==strlen(zColumn
)
101 && sqlite3_strnicmp(zCol
, zColumn
, strlen(zCol
))==0
103 p
->iCol
= sqlite3_column_int(pStmt
, 0);
107 sqlite3_finalize(pStmt
);
109 ofstError(p
, "no such column: %s.%s", zTable
, zColumn
);
110 goto rootAndColumn_exit
;
113 zSql
= sqlite3_mprintf("PRAGMA page_size");
114 rc
= sqlite3_prepare_v2(db
, zSql
, -1, &pStmt
, 0);
115 if( rc
) ofstError(p
, "%s: [%s]", sqlite3_errmsg(db
), zSql
);
117 if( p
->zErr
) goto rootAndColumn_exit
;
118 if( sqlite3_step(pStmt
)!=SQLITE_ROW
){
119 ofstError(p
, "cannot find page size");
121 p
->szPg
= sqlite3_column_int(pStmt
, 0);
123 sqlite3_finalize(pStmt
);
131 ** Pop a page from the stack
133 static void ofstPopPage(GState
*p
){
134 if( p
->nStack
<=0 ) return;
136 sqlite3_free(p
->aStack
[p
->nStack
]);
137 p
->pgno
= p
->aPgno
[p
->nStack
-1];
138 p
->aPage
= p
->aStack
[p
->nStack
-1];
143 ** Push a new page onto the stack.
145 static void ofstPushPage(GState
*p
, int pgno
){
148 if( p
->zErr
) return;
149 if( p
->nStack
>= ArraySize(p
->aStack
) ){
150 ofstError(p
, "page stack overflow");
153 p
->aPgno
[p
->nStack
] = pgno
;
154 p
->aStack
[p
->nStack
] = pPage
= sqlite3_malloc( p
->szPg
);
156 fprintf(stderr
, "out of memory\n");
162 fseek(p
->f
, (pgno
-1)*p
->szPg
, SEEK_SET
);
163 got
= fread(pPage
, 1, p
->szPg
, p
->f
);
165 ofstError(p
, "unable to read page %d", pgno
);
170 /* Read a two-byte integer at the given offset into the current page */
171 static int ofst2byte(GState
*p
, int ofst
){
172 int x
= p
->aPage
[ofst
];
173 return (x
<<8) + p
->aPage
[ofst
+1];
176 /* Read a four-byte integer at the given offset into the current page */
177 static int ofst4byte(GState
*p
, int ofst
){
178 int x
= p
->aPage
[ofst
];
179 x
= (x
<<8) + p
->aPage
[ofst
+1];
180 x
= (x
<<8) + p
->aPage
[ofst
+2];
181 x
= (x
<<8) + p
->aPage
[ofst
+3];
185 /* Read a variable-length integer. Update the offset */
186 static sqlite3_int64
ofstVarint(GState
*p
, int *pOfst
){
188 u8
*a
= &p
->aPage
[*pOfst
];
190 while( n
<8 && (a
[0] & 0x80)!=0 ){
191 x
= (x
<<7) + (a
[0] & 0x7f);
204 /* Return the absolute offset into a file for the given offset
205 ** into the current page */
206 static int ofstInFile(GState
*p
, int ofst
){
207 return p
->szPg
*(p
->pgno
-1) + ofst
;
210 /* Return the size (in bytes) of the data corresponding to the
211 ** given serial code */
212 static int ofstSerialSize(int scode
){
213 if( scode
<5 ) return scode
;
214 if( scode
==5 ) return 6;
215 if( scode
<8 ) return 8;
216 if( scode
<12 ) return 0;
220 /* Forward reference */
221 static void ofstWalkPage(GState
*, int);
223 /* Walk an interior btree page */
224 static void ofstWalkInteriorPage(GState
*p
){
230 nCell
= ofst2byte(p
, 3);
231 for(i
=0; i
<nCell
; i
++){
232 ofst
= ofst2byte(p
, 12+i
*2);
233 iChild
= ofst4byte(p
, ofst
);
234 ofstWalkPage(p
, iChild
);
235 if( p
->zErr
) return;
237 ofstWalkPage(p
, ofst4byte(p
, 8));
240 /* Walk a leaf btree page */
241 static void ofstWalkLeafPage(GState
*p
){
254 nCell
= ofst2byte(p
, 3);
255 for(i
=0; i
<nCell
; i
++){
256 ofst
= ofst2byte(p
, 8+i
*2);
257 nPayload
= ofstVarint(p
, &ofst
);
258 rowid
= ofstVarint(p
, &ofst
);
259 if( nPayload
> p
->szPg
-35 ){
260 sqlite3_snprintf(sizeof(zMsg
), zMsg
,
261 "# overflow rowid %lld", rowid
);
262 printf("%s\n", zMsg
);
266 nHdr
= ofstVarint(p
, &ofst
);
268 for(j
=0; j
<p
->iCol
; j
++){
269 scode
= ofstVarint(p
, &ofst
);
270 dataOfst
+= ofstSerialSize(scode
);
272 scode
= ofstVarint(p
, &ofst
);
273 sz
= ofstSerialSize(scode
);
274 sqlite3_snprintf(sizeof(zMsg
), zMsg
,
275 "rowid %12lld size %5d offset %8d",
276 rowid
, sz
, ofstInFile(p
, dataOfst
));
277 printf("%s\n", zMsg
);
282 ** Output results from a single page.
284 static void ofstWalkPage(GState
*p
, int pgno
){
285 if( p
->zErr
) return;
286 ofstPushPage(p
, pgno
);
287 if( p
->zErr
) return;
288 if( p
->aPage
[0]==5 ){
289 ofstWalkInteriorPage(p
);
290 }else if( p
->aPage
[0]==13 ){
293 ofstError(p
, "page %d has a faulty type byte: %d", pgno
, p
->aPage
[0]);
298 int main(int argc
, char **argv
){
300 memset(&g
, 0, sizeof(g
));
301 if( argc
>2 && strcmp(argv
[1],"--trace")==0 ){
307 fprintf(stderr
, "Usage: %s DATABASE TABLE COLUMN\n", *argv
);
310 ofstRootAndColumn(&g
, argv
[1], argv
[2], argv
[3]);
312 fprintf(stderr
, "%s\n", g
.zErr
);
315 ofstTrace(&g
, "# szPg = %d\n", g
.szPg
);
316 ofstTrace(&g
, "# iRoot = %d\n", g
.iRoot
);
317 ofstTrace(&g
, "# iCol = %d\n", g
.iCol
);
318 g
.f
= fopen(argv
[1], "rb");
320 fprintf(stderr
, "cannot open \"%s\"\n", argv
[1]);
323 ofstWalkPage(&g
, g
.iRoot
);
325 fprintf(stderr
, "%s\n", g
.zErr
);