Annotation of embedaddon/sqlite3/tool/offsets.c, revision 1.1.1.1

1.1       misho       1: /*
                      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.
                      7: */
                      8: #include "sqlite3.h"
                      9: #include <stdio.h>
                     10: #include <stdlib.h>
                     11: #include <stdarg.h>
                     12: #include <string.h>
                     13: 
                     14: typedef unsigned char u8;
                     15: typedef struct GState GState;
                     16: 
                     17: #define ArraySize(X)   (sizeof(X)/sizeof(X[0]))
                     18: 
                     19: /*
                     20: ** Global state information for this program.
                     21: */
                     22: struct GState {
                     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 */
                     34: };
                     35: 
                     36: /*
                     37: ** Write an error.
                     38: */
                     39: static void ofstError(GState *p, const char *zFormat, ...){
                     40:   va_list ap;
                     41:   sqlite3_free(p->zErr);
                     42:   va_start(ap, zFormat);
                     43:   p->zErr = sqlite3_vmprintf(zFormat, ap);
                     44:   va_end(ap);
                     45: }
                     46: 
                     47: /*
                     48: ** Write a trace message
                     49: */
                     50: static void ofstTrace(GState *p, const char *zFormat, ...){
                     51:   va_list ap;
                     52:   if( p->bTrace ){
                     53:     va_start(ap, zFormat);
                     54:     vprintf(zFormat, ap);
                     55:     va_end(ap);
                     56:   }
                     57: }
                     58: 
                     59: /*
                     60: ** Find the root page of the table and the column number of the column.
                     61: */
                     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 */
                     67: ){
                     68:   sqlite3 *db = 0;
                     69:   sqlite3_stmt *pStmt = 0;
                     70:   char *zSql = 0;
                     71:   int rc;
                     72:   if( p->zErr ) return;
                     73:   rc = sqlite3_open(zFile, &db);
                     74:   if( rc ){
                     75:     ofstError(p, "cannot open database file \"%s\"", zFile);
                     76:     goto rootAndColumn_exit;
                     77:   }
                     78:   zSql = sqlite3_mprintf("SELECT rootpage FROM sqlite_master WHERE name=%Q",
                     79:                          zTable);
                     80:   rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
                     81:   if( rc ) ofstError(p, "%s: [%s]", sqlite3_errmsg(db), zSql);
                     82:   sqlite3_free(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;
                     88:   }
                     89:   p->iRoot = sqlite3_column_int(pStmt , 0);
                     90:   sqlite3_finalize(pStmt);
                     91: 
                     92:   p->iCol = -1;
                     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);
                     96:   sqlite3_free(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
                    102:     ){
                    103:       p->iCol = sqlite3_column_int(pStmt, 0);
                    104:       break;
                    105:     }
                    106:   }
                    107:   sqlite3_finalize(pStmt);
                    108:   if( p->iCol<0 ){
                    109:     ofstError(p, "no such column: %s.%s", zTable, zColumn);
                    110:     goto rootAndColumn_exit;
                    111:   }
                    112: 
                    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);
                    116:   sqlite3_free(zSql);
                    117:   if( p->zErr ) goto rootAndColumn_exit;
                    118:   if( sqlite3_step(pStmt)!=SQLITE_ROW ){
                    119:     ofstError(p, "cannot find page size");
                    120:   }else{
                    121:     p->szPg = sqlite3_column_int(pStmt, 0);
                    122:   }
                    123:   sqlite3_finalize(pStmt);
                    124: 
                    125: rootAndColumn_exit:
                    126:   sqlite3_close(db);
                    127:   return;
                    128: }
                    129: 
                    130: /*
                    131: ** Pop a page from the stack
                    132: */
                    133: static void ofstPopPage(GState *p){
                    134:   if( p->nStack<=0 ) return;
                    135:   p->nStack--;
                    136:   sqlite3_free(p->aStack[p->nStack]);
                    137:   p->pgno = p->aPgno[p->nStack-1];
                    138:   p->aPage = p->aStack[p->nStack-1];
                    139: }
                    140: 
                    141: 
                    142: /*
                    143: ** Push a new page onto the stack.
                    144: */
                    145: static void ofstPushPage(GState *p, int pgno){
                    146:   u8 *pPage;
                    147:   size_t got;
                    148:   if( p->zErr ) return;
                    149:   if( p->nStack >= ArraySize(p->aStack) ){
                    150:     ofstError(p, "page stack overflow");
                    151:     return;
                    152:   }
                    153:   p->aPgno[p->nStack] = pgno;
                    154:   p->aStack[p->nStack] = pPage = sqlite3_malloc( p->szPg );
                    155:   if( pPage==0 ){
                    156:     fprintf(stderr, "out of memory\n");
                    157:     exit(1);
                    158:   }
                    159:   p->nStack++;
                    160:   p->aPage = pPage;
                    161:   p->pgno = pgno;
                    162:   fseek(p->f, (pgno-1)*p->szPg, SEEK_SET);
                    163:   got = fread(pPage, 1, p->szPg, p->f);
                    164:   if( got!=p->szPg ){
                    165:     ofstError(p, "unable to read page %d", pgno);
                    166:     ofstPopPage(p);
                    167:   }
                    168: }
                    169: 
                    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];
                    174: }
                    175: 
                    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];
                    182:   return x;
                    183: }
                    184: 
                    185: /* Read a variable-length integer.  Update the offset */
                    186: static sqlite3_int64 ofstVarint(GState *p, int *pOfst){
                    187:   sqlite3_int64 x = 0;
                    188:   u8 *a = &p->aPage[*pOfst];
                    189:   int n = 0;
                    190:   while( n<8 && (a[0] & 0x80)!=0 ){
                    191:     x = (x<<7) + (a[0] & 0x7f);
                    192:     n++;
                    193:     a++;
                    194:   }
                    195:   if( n==8 ){
                    196:     x = (x<<8) + a[0];
                    197:   }else{
                    198:     x = (x<<7) + a[0];
                    199:   }
                    200:   *pOfst += (n+1);
                    201:   return x;
                    202: }
                    203: 
                    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;
                    208: }
                    209: 
                    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;
                    217:   return (scode-12)/2;
                    218: }
                    219: 
                    220: /* Forward reference */
                    221: static void ofstWalkPage(GState*, int);
                    222: 
                    223: /* Walk an interior btree page */
                    224: static void ofstWalkInteriorPage(GState *p){
                    225:   int nCell;
                    226:   int i;
                    227:   int ofst;
                    228:   int iChild;
                    229: 
                    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;
                    236:   }
                    237:   ofstWalkPage(p, ofst4byte(p, 8));
                    238: }
                    239: 
                    240: /* Walk a leaf btree page */
                    241: static void ofstWalkLeafPage(GState *p){
                    242:   int nCell;
                    243:   int i;
                    244:   int ofst;
                    245:   int nPayload;
                    246:   sqlite3_int64 rowid;
                    247:   int nHdr;
                    248:   int j;
                    249:   int scode;
                    250:   int sz;
                    251:   int dataOfst;
                    252:   char zMsg[200];
                    253: 
                    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);
                    263:       continue;
                    264:     }
                    265:     dataOfst = ofst;
                    266:     nHdr = ofstVarint(p, &ofst);
                    267:     dataOfst += nHdr;
                    268:     for(j=0; j<p->iCol; j++){
                    269:       scode = ofstVarint(p, &ofst);
                    270:       dataOfst += ofstSerialSize(scode);
                    271:     }
                    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);
                    278:   }
                    279: }
                    280: 
                    281: /*
                    282: ** Output results from a single page.
                    283: */
                    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 ){
                    291:     ofstWalkLeafPage(p);
                    292:   }else{
                    293:     ofstError(p, "page %d has a faulty type byte: %d", pgno, p->aPage[0]);
                    294:   }
                    295:   ofstPopPage(p);
                    296: }
                    297: 
                    298: int main(int argc, char **argv){
                    299:   GState g;
                    300:   memset(&g, 0, sizeof(g));
                    301:   if( argc>2 && strcmp(argv[1],"--trace")==0 ){
                    302:     g.bTrace = 1;
                    303:     argc--;
                    304:     argv++;
                    305:   }
                    306:   if( argc!=4 ){
                    307:     fprintf(stderr, "Usage: %s DATABASE TABLE COLUMN\n", *argv);
                    308:     exit(1);
                    309:   }
                    310:   ofstRootAndColumn(&g, argv[1], argv[2], argv[3]);
                    311:   if( g.zErr ){
                    312:     fprintf(stderr, "%s\n", g.zErr);
                    313:     exit(1);
                    314:   }
                    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");
                    319:   if( g.f==0 ){
                    320:     fprintf(stderr, "cannot open \"%s\"\n", argv[1]);
                    321:     exit(1);
                    322:   }
                    323:   ofstWalkPage(&g, g.iRoot);
                    324:   if( g.zErr ){
                    325:     fprintf(stderr, "%s\n", g.zErr);
                    326:     exit(1);
                    327:   }
                    328:   return 0; 
                    329: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>