]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Enhance fts3view to show decodes of segments and doclists.
authordrh <drh@noemail.net>
Tue, 27 Mar 2012 00:34:04 +0000 (00:34 +0000)
committerdrh <drh@noemail.net>
Tue, 27 Mar 2012 00:34:04 +0000 (00:34 +0000)
FossilOrigin-Name: 6d09de231b68dd9520d99c65d133f26e90eb784f

ext/fts3/tool/fts3view.c
manifest
manifest.uuid

index fbda5016ccdc14138d78e74c5d419652d21f0120..1ecb581171badd054467f650c477f6bf7fdb4199 100644 (file)
@@ -18,6 +18,7 @@
 #include <stdarg.h>
 #include <stdlib.h>
 #include <string.h>
+#include <ctype.h>
 #include "sqlite3.h"
 
 /*
@@ -436,7 +437,7 @@ static void showSegdirMap(sqlite3 *db, const char *zTab){
 
   printf("Number of inverted indices............... %3d\n", mxIndex+1);
   pStmt = prepare(db,
-    "SELECT level, idx, start_block, leaves_end_block, end_block"
+    "SELECT level, idx, start_block, leaves_end_block, end_block, rowid"
     "  FROM '%q_segdir'"
     " WHERE level/1024==?"
     " ORDER BY level DESC, idx",
@@ -464,10 +465,9 @@ static void showSegdirMap(sqlite3 *db, const char *zTab){
       }else{
         printf("         idx %2d", iIdx);
       }
+      printf("  root     r%lld\n", sqlite3_column_int64(pStmt, 5));
       if( iLEnd>iStart ){
         sqlite3_int64 iLower, iPrev, iX;
-        printf("  leaves %9lld thru %9lld  (%lld blocks)\n",
-               iStart, iLEnd, iLEnd - iStart + 1);
         if( iLEnd+1<=iEnd ){
           sqlite3_bind_int64(pStmt2, 1, iLEnd+1);
           sqlite3_bind_int64(pStmt2, 2, iEnd);
@@ -486,8 +486,8 @@ static void showSegdirMap(sqlite3 *db, const char *zTab){
           sqlite3_reset(pStmt2);
           if( iLower>=0 ) printTreeLine(iLower, iPrev);
         }
-      }else{
-        printf("  root only\n");
+        printf("                 leaves %9lld thru %9lld  (%lld blocks)\n",
+               iStart, iLEnd, iLEnd - iStart + 1);
       }
     }
     sqlite3_reset(pStmt);
@@ -496,17 +496,249 @@ static void showSegdirMap(sqlite3 *db, const char *zTab){
   sqlite3_finalize(pStmt2);
 }
 
+/*
+** Decode a single segment block and display the results on stdout.
+*/
+static void decodeSegment(
+  const unsigned char *aData,   /* Content to print */
+  int nData                     /* Number of bytes of content */
+){
+  sqlite3_int64 iChild;
+  sqlite3_int64 iPrefix;
+  sqlite3_int64 nTerm;
+  sqlite3_int64 n;
+  sqlite3_int64 iDocsz;
+  int iHeight;
+  int i = 0;
+  int cnt = 0;
+  char zTerm[1000];
+
+  i += getVarint(aData, &n);
+  iHeight = (int)n;
+  printf("height: %d\n", iHeight);
+  if( iHeight>0 ){
+    i += getVarint(aData+i, &iChild);
+    printf("left-child: %lld\n", iChild);
+  }
+  while( i<nData ){
+    if( (cnt++)>0 ){
+      i += getVarint(aData+i, &iPrefix);
+    }else{
+      iPrefix = 0;
+    }
+    i += getVarint(aData+i, &nTerm);
+    if( iPrefix+nTerm+1 >= sizeof(zTerm) ){
+      fprintf(stderr, "term to long\n");
+      exit(1);
+    }
+    memcpy(zTerm+iPrefix, aData+i, nTerm);
+    zTerm[iPrefix+nTerm] = 0;
+    i += nTerm;
+    if( iHeight==0 ){
+      i += getVarint(aData+i, &iDocsz);
+      printf("term: %-25s doclist %7lld bytes offset %d\n", zTerm, iDocsz, i);
+      i += iDocsz;
+    }else{
+      printf("term: %-25s child %lld\n", zTerm, ++iChild);
+    }
+  }
+}
+  
+  
+/*
+** Print a a blob as hex and ascii.
+*/
+static void printBlob(
+  const unsigned char *aData,   /* Content to print */
+  int nData                     /* Number of bytes of content */
+){
+  int i, j;
+  const char *zOfstFmt;
+  const int perLine = 16;
+
+  if( (nData&~0xfff)==0 ){
+    zOfstFmt = " %03x: ";
+  }else if( (nData&~0xffff)==0 ){
+    zOfstFmt = " %04x: ";
+  }else if( (nData&~0xfffff)==0 ){
+    zOfstFmt = " %05x: ";
+  }else if( (nData&~0xffffff)==0 ){
+    zOfstFmt = " %06x: ";
+  }else{
+    zOfstFmt = " %08x: ";
+  }
+
+  for(i=0; i<nData; i += perLine){
+    fprintf(stdout, zOfstFmt, i);
+    for(j=0; j<perLine; j++){
+      if( i+j>nData ){
+        fprintf(stdout, "   ");
+      }else{
+        fprintf(stdout,"%02x ", aData[i+j]);
+      }
+    }
+    for(j=0; j<perLine; j++){
+      if( i+j>nData ){
+        fprintf(stdout, " ");
+      }else{
+        fprintf(stdout,"%c", isprint(aData[i+j]) ? aData[i+j] : '.');
+      }
+    }
+    fprintf(stdout,"\n");
+  }
+}
+
+/*
+** Convert text to a 64-bit integer
+*/
+static sqlite3_int64 atoi64(const char *z){
+  sqlite3_int64 v = 0;
+  while( z[0]>='0' && z[0]<='9' ){
+     v = v*10 + z[0] - '0';
+     z++;
+  }
+  return v;
+}
+
+/*
+** Return a prepared statement which, when stepped, will return in its
+** first column the blob associated with segment zId.  If zId begins with
+** 'r' then it is a rowid of a %_segdir entry.  Otherwise it is a
+** %_segment entry.
+*/
+static sqlite3_stmt *prepareToGetSegment(
+  sqlite3 *db,         /* The database */
+  const char *zTab,    /* The FTS3/4 table name */
+  const char *zId      /* ID of the segment to open */
+){
+  sqlite3_stmt *pStmt;
+  if( zId[0]=='r' ){
+    pStmt = prepare(db, "SELECT root FROM '%q_segdir' WHERE rowid=%lld",
+                    zTab, atoi64(zId+1));
+  }else{
+    pStmt = prepare(db, "SELECT block FROM '%q_segments' WHERE blockid=%lld",
+                    zTab, atoi64(zId));
+  }
+  return pStmt;
+}
+
+/*
+** Print the content of a segment or of the root of a segdir.  The segment
+** or root is identified by azExtra[0].  If the first character of azExtra[0]
+** is 'r' then the remainder is the integer rowid of the %_segdir entry.
+** If the first character of azExtra[0] is not 'r' then, then all of
+** azExtra[0] is an integer which is the block number.
+**
+** If the --raw option is present in azExtra, then a hex dump is provided.
+** Otherwise a decoding is shown.
+*/
+static void showSegment(sqlite3 *db, const char *zTab){
+  const unsigned char *aData;
+  int nData;
+  sqlite3_stmt *pStmt;
+
+  pStmt = prepareToGetSegment(db, zTab, azExtra[0]);
+  if( sqlite3_step(pStmt)!=SQLITE_ROW ){
+    sqlite3_finalize(pStmt);
+    return;
+  }
+  nData = sqlite3_column_bytes(pStmt, 0);
+  aData = sqlite3_column_blob(pStmt, 0);
+  printf("Segment %s of size %d bytes:\n", azExtra[0], nData);
+  if( findOption("raw", 0, 0)!=0 ){
+    printBlob(aData, nData);
+  }else{
+    decodeSegment(aData, nData);
+  }
+  sqlite3_finalize(pStmt);
+}
+
+/*
+** Decode a single doclist and display the results on stdout.
+*/
+static void decodeDoclist(
+  const unsigned char *aData,   /* Content to print */
+  int nData                     /* Number of bytes of content */
+){
+  sqlite3_int64 iPrevDocid = 0;
+  sqlite3_int64 iDocid;
+  sqlite3_int64 iPos;
+  sqlite3_int64 iPrevPos = 0;
+  sqlite3_int64 iCol;
+  int i = 0;
+
+  while( i<nData ){
+    i += getVarint(aData+i, &iDocid);
+    printf("docid %lld col0", iDocid+iPrevDocid);
+    iPrevDocid += iDocid;
+    iPrevPos = 0;
+    while( 1 ){
+      i += getVarint(aData+i, &iPos);
+      if( iPos==1 ){
+        i += getVarint(aData+i, &iCol);
+        printf(" col%lld", iCol);
+        iPrevPos = 0;
+      }else if( iPos==0 ){
+        printf("\n");
+        break;
+      }else{
+        printf(" %lld", iPrevPos + iPos - 2);
+        iPrevPos = iPos - 2;
+      }
+    }
+  }
+}
+  
+
+/*
+** Print the content of a doclist.  The segment or segdir-root is
+** identified by azExtra[0].  If the first character of azExtra[0]
+** is 'r' then the remainder is the integer rowid of the %_segdir entry.
+** If the first character of azExtra[0] is not 'r' then, then all of
+** azExtra[0] is an integer which is the block number.  The offset
+** into the segment is identified by azExtra[1].  The size of the doclist
+** is azExtra[2].
+**
+** If the --raw option is present in azExtra, then a hex dump is provided.
+** Otherwise a decoding is shown.
+*/
+static void showDoclist(sqlite3 *db, const char *zTab){
+  const unsigned char *aData;
+  sqlite3_int64 offset, nData;
+  sqlite3_stmt *pStmt;
+
+  offset = atoi64(azExtra[1]);
+  nData = atoi64(azExtra[2]);
+  pStmt = prepareToGetSegment(db, zTab, azExtra[0]);
+  if( sqlite3_step(pStmt)!=SQLITE_ROW ){
+    sqlite3_finalize(pStmt);
+    return;
+  }
+  aData = sqlite3_column_blob(pStmt, 0);
+  printf("Doclist at %s offset %lld of size %lld bytes:\n",
+         azExtra[0], offset, nData);
+  if( findOption("raw", 0, 0)!=0 ){
+    printBlob(aData+offset, nData);
+  }else{
+    decodeDoclist(aData+offset, nData);
+  }
+  sqlite3_finalize(pStmt);
+}
+
+
 
 static void usage(const char *argv0){
   fprintf(stderr, "Usage: %s DATABASE\n"
                   "   or: %s DATABASE FTS3TABLE ARGS...\n", argv0, argv0);
   fprintf(stderr,
     "ARGS:\n"
-    "  schema                        FTS table schema\n"
-    "  segdir                        directory of segments\n"
-    "  segment-stats                 information about segment sizes\n"
-    "  stat                          content of the %%_stat table\n"
-    "  vocabulary --top N            information on the document vocabulary\n"
+    "  doclist BLOCKID OFFSET SIZE [--raw]       Decode a doclist\n"
+    "  schema                                    FTS table schema\n"
+    "  segdir                                    directory of segments\n"
+    "  segment BLOCKID [--raw]                   content of a segment\n"
+    "  segment-stats                             info on segment sizes\n"
+    "  stat                                      the %%_stat table\n"
+    "  vocabulary [--top N]                      document vocabulary\n"
   );
   exit(1);
 }
@@ -545,10 +777,16 @@ int main(int argc, char **argv){
   zCmd = argv[3];
   nExtra = argc-4;
   azExtra = argv+4;
-  if( strcmp(zCmd,"schema")==0 ){
+  if( strcmp(zCmd,"doclist")==0 ){
+    if( argc<7 ) usage(argv[0]);
+    showDoclist(db, zTab);
+  }else if( strcmp(zCmd,"schema")==0 ){
     showSchema(db, zTab);
   }else if( strcmp(zCmd,"segdir")==0 ){
     showSegdirMap(db, zTab);
+  }else if( strcmp(zCmd,"segment")==0 ){
+    if( argc<5 ) usage(argv[0]);
+    showSegment(db, zTab);
   }else if( strcmp(zCmd,"segment-stats")==0 ){
     showSegmentStats(db, zTab);
   }else if( strcmp(zCmd,"stat")==0 ){
index 42ffd4a36c923dc077c5afc64b2738b5029e75e4..21d296b5275a5071b64556126892eb9dc5b148ce 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Add\sthe\sfts3view\sutility\sprogram.
-D 2012-03-26T21:57:53.278
+C Enhance\sfts3view\sto\sshow\sdecodes\sof\ssegments\sand\sdoclists.
+D 2012-03-27T00:34:04.336
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in 2f37e468503dbe79d35c9f6dffcf3fae1ae9ec20
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -81,7 +81,7 @@ F ext/fts3/fts3_tokenizer1.c 5c98225a53705e5ee34824087478cf477bdb7004
 F ext/fts3/fts3_write.c 6014014cf0257d314d29d7eb50e0c88d85356d65
 F ext/fts3/fts3speed.tcl b54caf6a18d38174f1a6e84219950d85e98bb1e9
 F ext/fts3/mkfts3amal.tcl 252ecb7fe6467854f2aa237bf2c390b74e71f100
-F ext/fts3/tool/fts3view.c 005efba99f4de1ab104456f7652f955603a81d7f
+F ext/fts3/tool/fts3view.c 71d6149a268e8375cd9e5c8224868fa7460614c3
 F ext/icu/README.txt bf8461d8cdc6b8f514c080e4e10dc3b2bbdfefa9
 F ext/icu/icu.c eb9ae1d79046bd7871aa97ee6da51eb770134b5a
 F ext/icu/sqliteicu.h 728867a802baa5a96de7495e9689a8e01715ef37
@@ -1000,7 +1000,7 @@ F tool/tostr.awk e75472c2f98dd76e06b8c9c1367f4ab07e122d06
 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
 F tool/warnings-clang.sh 9f406d66e750e8ac031c63a9ef3248aaa347ef2a
 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381
-P a18c103121529c2e3c6a8ada16a4c40d14080670
-R ad0002e6aa190f63417466651f9099fc
+P f936c8ea16d21345fd1622272dc7e9850acb2493
+R a7bfe1f32748865cb6cf2cbcda903177
 U drh
-Z 38d7fb610b5e9fceb6186edb4298f4d3
+Z fcd448737f1da3e5558671112d888fce
index 2fd4d0cb571d66e8d9b2509091f4691714fd8d09..3348c6a1f556bfc3c1bcfcc42a3d4790deb058a8 100644 (file)
@@ -1 +1 @@
-f936c8ea16d21345fd1622272dc7e9850acb2493
\ No newline at end of file
+6d09de231b68dd9520d99c65d133f26e90eb784f
\ No newline at end of file