File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / sqlite3 / tool / offsets.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 17:04:17 2012 UTC (12 years, 4 months ago) by misho
Branches: sqlite3, MAIN
CVS tags: v3_7_10, HEAD
sqlite3

    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>