Annotation of embedaddon/sqlite3/tool/offsets.c, revision 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>