]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add the "loadfts" program, for performance testing the loading of data into fts3...
authordan <dan@noemail.net>
Mon, 28 Jul 2014 20:14:02 +0000 (20:14 +0000)
committerdan <dan@noemail.net>
Mon, 28 Jul 2014 20:14:02 +0000 (20:14 +0000)
FossilOrigin-Name: 770b9540c19ad1e3d24adff382332bf032065efd

ext/fts5/fts5_aux.c
ext/fts5/fts5_config.c
ext/fts5/fts5_expr.c
main.mk
manifest
manifest.uuid
tool/loadfts.c [new file with mode: 0644]
tool/mksqlite3c.tcl

index 2426c1dc51d8ad558cb49ba37c8f78aab8deaf12..5214296e355fb6e29625eb12b77ba83aa38f67f9 100644 (file)
 #include "fts5Int.h"
 #include <math.h>
 
-typedef struct SnippetPhrase SnippetPhrase;
-typedef struct SnippetIter SnippetIter;
+typedef struct SnipPhrase SnipPhrase;
+typedef struct SnipIter SnipIter;
 typedef struct SnippetCtx SnippetCtx;
 
-struct SnippetPhrase {
+struct SnipPhrase {
   u64 mask;                       /* Current mask */
   int nToken;                     /* Tokens in this phrase */
   int i;                          /* Current offset in phrase poslist */
   i64 iPos;                       /* Next position in phrase (-ve -> EOF) */
 };
 
-struct SnippetIter {
+struct SnipIter {
   i64 iLast;                      /* Last token position of current snippet */
   int nScore;                     /* Score of current snippet */
 
   const Fts5ExtensionApi *pApi;
   Fts5Context *pFts;
-  u64 szmask;                     /* Mask used to on SnippetPhrase.mask */
+  u64 szmask;                     /* Mask used to on SnipPhrase.mask */
   int nPhrase;                    /* Number of phrases */
-  SnippetPhrase aPhrase[0];       /* Array of size nPhrase */
+  SnipPhrase aPhrase[0];       /* Array of size nPhrase */
 };
 
 struct SnippetCtx {
@@ -71,13 +71,13 @@ static int fts5SnippetCallback(
 /*
 ** Set pIter->nScore to the score for the current entry.
 */
-static void fts5SnippetCalculateScore(SnippetIter *pIter){
+static void fts5SnippetCalculateScore(SnipIter *pIter){
   int i;
   int nScore = 0;
   assert( pIter->iLast>=0 );
 
   for(i=0; i<pIter->nPhrase; i++){
-    SnippetPhrase *p = &pIter->aPhrase[i];
+    SnipPhrase *p = &pIter->aPhrase[i];
     u64 mask = p->mask;
     if( mask ){
       u64 j;
@@ -94,21 +94,21 @@ static void fts5SnippetCalculateScore(SnippetIter *pIter){
 /*
 ** Allocate a new snippet iter.
 */
-static int fts5SnippetIterNew(
+static int fts5SnipIterNew(
   const Fts5ExtensionApi *pApi,   /* API offered by current FTS version */
   Fts5Context *pFts,              /* First arg to pass to pApi functions */
   int nToken,                     /* Number of tokens in snippets */
-  SnippetIter **ppIter            /* OUT: New object */
+  SnipIter **ppIter            /* OUT: New object */
 ){
   int i;                          /* Counter variable */
-  SnippetIter *pIter;             /* New iterator object */
+  SnipIter *pIter;             /* New iterator object */
   int nByte;                      /* Bytes of space to allocate */
   int nPhrase;                    /* Number of phrases in query */
 
   *ppIter = 0;
   nPhrase = pApi->xPhraseCount(pFts);
-  nByte = sizeof(SnippetIter) + nPhrase * sizeof(SnippetPhrase);
-  pIter = (SnippetIter*)sqlite3_malloc(nByte);
+  nByte = sizeof(SnipIter) + nPhrase * sizeof(SnipPhrase);
+  pIter = (SnipIter*)sqlite3_malloc(nByte);
   if( pIter==0 ) return SQLITE_NOMEM;
   memset(pIter, 0, nByte);
 
@@ -129,16 +129,16 @@ static int fts5SnippetIterNew(
 /*
 ** Set the iterator to point to the first candidate snippet.
 */
-static void fts5SnippetIterFirst(SnippetIter *pIter){
+static void fts5SnipIterFirst(SnipIter *pIter){
   const Fts5ExtensionApi *pApi = pIter->pApi;
   Fts5Context *pFts = pIter->pFts;
   int i;                          /* Used to iterate through phrases */
-  SnippetPhrase *pMin = 0;        /* Phrase with first match */
+  SnipPhrase *pMin = 0;        /* Phrase with first match */
 
-  memset(pIter->aPhrase, 0, sizeof(SnippetPhrase) * pIter->nPhrase);
+  memset(pIter->aPhrase, 0, sizeof(SnipPhrase) * pIter->nPhrase);
 
   for(i=0; i<pIter->nPhrase; i++){
-    SnippetPhrase *p = &pIter->aPhrase[i];
+    SnipPhrase *p = &pIter->aPhrase[i];
     p->nToken = pApi->xPhraseSize(pFts, i);
     pApi->xPoslist(pFts, i, &p->i, &p->iPos);
     if( p->iPos>=0 && (pMin==0 || p->iPos<pMin->iPos) ){
@@ -156,26 +156,26 @@ static void fts5SnippetIterFirst(SnippetIter *pIter){
 /*
 ** Advance the snippet iterator to the next candidate snippet.
 */
-static void fts5SnippetIterNext(SnippetIter *pIter){
+static void fts5SnipIterNext(SnipIter *pIter){
   const Fts5ExtensionApi *pApi = pIter->pApi;
   Fts5Context *pFts = pIter->pFts;
   int nPhrase = pIter->nPhrase;
   int i;                          /* Used to iterate through phrases */
-  SnippetPhrase *pMin = 0;
+  SnipPhrase *pMin = 0;
 
   for(i=0; i<nPhrase; i++){
-    SnippetPhrase *p = &pIter->aPhrase[i];
+    SnipPhrase *p = &pIter->aPhrase[i];
     if( p->iPos>=0 && (pMin==0 || p->iPos<pMin->iPos) ) pMin = p;
   }
 
   if( pMin==0 ){
-    /* pMin==0 indicates that the SnippetIter is at EOF. */
+    /* pMin==0 indicates that the SnipIter is at EOF. */
     pIter->iLast = -1;
   }else{
     i64 nShift = pMin->iPos - pIter->iLast;
     assert( nShift>=0 );
     for(i=0; i<nPhrase; i++){
-      SnippetPhrase *p = &pIter->aPhrase[i];
+      SnipPhrase *p = &pIter->aPhrase[i];
       if( nShift>=63 ){
         p->mask = 0;
       }else{
@@ -191,7 +191,7 @@ static void fts5SnippetIterNext(SnippetIter *pIter){
   }
 }
 
-static void fts5SnippetIterFree(SnippetIter *pIter){
+static void fts5SnipIterFree(SnipIter *pIter){
   if( pIter ){
     sqlite3_free(pIter);
   }
@@ -200,7 +200,7 @@ static void fts5SnippetIterFree(SnippetIter *pIter){
 static int fts5SnippetText(
   const Fts5ExtensionApi *pApi,   /* API offered by current FTS version */
   Fts5Context *pFts,              /* First arg to pass to pApi functions */
-  SnippetIter *pIter,             /* Snippet to write to buffer */
+  SnipIter *pIter,             /* Snippet to write to buffer */
   int nToken,                     /* Size of desired snippet in tokens */
   const char *zStart,
   const char *zFinal,
@@ -299,7 +299,7 @@ static int fts5SnippetText(
       /* Check if this is the first token of any phrase match. */
       int ip;
       for(ip=0; ip<pIter->nPhrase; ip++){
-        SnippetPhrase *pPhrase = &pIter->aPhrase[ip];
+        SnipPhrase *pPhrase = &pIter->aPhrase[ip];
         u64 m = (1 << (iLast - i - pPhrase->nToken + 1));
 
         if( i<=iLast && (pPhrase->mask & m) ){
@@ -368,7 +368,7 @@ static void fts5SnippetFunction(
   int nToken = -15;
   int nAbs;
   int rc;
-  SnippetIter *pIter = 0;
+  SnipIter *pIter = 0;
 
   if( nVal>=1 ) zStart = (const char*)sqlite3_value_text(apVal[0]);
   if( nVal>=2 ) zFinal = (const char*)sqlite3_value_text(apVal[1]);
@@ -379,20 +379,20 @@ static void fts5SnippetFunction(
   }
   nAbs = nToken * (nToken<0 ? -1 : 1);
 
-  rc = fts5SnippetIterNew(pApi, pFts, nAbs, &pIter);
+  rc = fts5SnipIterNew(pApi, pFts, nAbs, &pIter);
   if( rc==SQLITE_OK ){
     Fts5Buffer buf;               /* Result buffer */
     int nBestScore = 0;           /* Score of best snippet found */
 
-    for(fts5SnippetIterFirst(pIter); 
+    for(fts5SnipIterFirst(pIter); 
         pIter->iLast>=0; 
-        fts5SnippetIterNext(pIter)
+        fts5SnipIterNext(pIter)
     ){
       if( pIter->nScore>nBestScore ) nBestScore = pIter->nScore;
     }
-    for(fts5SnippetIterFirst(pIter); 
+    for(fts5SnipIterFirst(pIter); 
         pIter->iLast>=0; 
-        fts5SnippetIterNext(pIter)
+        fts5SnipIterNext(pIter)
     ){
       if( pIter->nScore==nBestScore ) break;
     }
@@ -405,7 +405,7 @@ static void fts5SnippetFunction(
     sqlite3_free(buf.p);
   }
 
-  fts5SnippetIterFree(pIter);
+  fts5SnipIterFree(pIter);
   if( rc!=SQLITE_OK ){
     sqlite3_result_error_code(pCtx, rc);
   }
index bbcbc5e0e59424cee6a41e80b183130d8ced06be..5bed69def35797ddb648ec615e4c7ed18ad3c2ee 100644 (file)
@@ -113,7 +113,7 @@ static char *fts5Strdup(const char *z){
   return sqlite3_mprintf("%s", z);
 }
 
-void sqlite3Fts3SimpleTokenizerModule(sqlite3_tokenizer_module**);
+void sqlite3Fts3SimpleTokenizerModule(sqlite3_tokenizer_module const**);
 
 /*
 ** Allocate an instance of the default tokenizer ("simple") at 
@@ -121,7 +121,7 @@ void sqlite3Fts3SimpleTokenizerModule(sqlite3_tokenizer_module**);
 ** code if an error occurs.
 */
 static int fts5ConfigDefaultTokenizer(Fts5Config *pConfig){
-  sqlite3_tokenizer_module *pMod; /* Tokenizer module "simple" */
+  const sqlite3_tokenizer_module *pMod; /* Tokenizer module "simple" */
   sqlite3_tokenizer *pTokenizer;  /* Tokenizer instance */
   int rc;                         /* Return code */
 
index ab9b307bc29f110b5222050b3b91ad2f034d0dc8..2fd7f63f761c9e8aca8a265e92a4265a606146fe 100644 (file)
@@ -997,7 +997,7 @@ i64 sqlite3Fts5ExprRowid(Fts5Expr *p){
 ** It is the responsibility of the caller to eventually free the returned
 ** buffer using sqlite3_free(). If an OOM error occurs, NULL is returned. 
 */
-static char *fts5Strdup(const char *pIn, int nIn){
+static char *fts5Strndup(const char *pIn, int nIn){
   char *zRet = (char*)sqlite3_malloc(nIn+1);
   if( zRet ){
     memcpy(zRet, pIn, nIn);
@@ -1007,7 +1007,7 @@ static char *fts5Strdup(const char *pIn, int nIn){
 }
 
 static int fts5ParseStringFromToken(Fts5Token *pToken, char **pz){
-  *pz = fts5Strdup(pToken->p, pToken->n);
+  *pz = fts5Strndup(pToken->p, pToken->n);
   if( *pz==0 ) return SQLITE_NOMEM;
   return SQLITE_OK;
 }
@@ -1115,7 +1115,7 @@ static int fts5ParseTokenize(
 
   pTerm = &pPhrase->aTerm[pPhrase->nTerm++];
   memset(pTerm, 0, sizeof(Fts5ExprTerm));
-  pTerm->zTerm = fts5Strdup(pToken, nToken);
+  pTerm->zTerm = fts5Strndup(pToken, nToken);
 
   return pTerm->zTerm ? SQLITE_OK : SQLITE_NOMEM;
 }
diff --git a/main.mk b/main.mk
index a1582fb6dcf2513e0678257d8e8d56599c9594c3..1a75c39827f00768bfbd7f02282bd53da400f35d 100644 (file)
--- a/main.mk
+++ b/main.mk
@@ -224,6 +224,18 @@ SRC += \
   $(TOP)/ext/rtree/rtree.h \
   $(TOP)/ext/rtree/rtree.c
 
+SRC += \
+   $(TOP)/ext/fts5/fts5.h \
+   $(TOP)/ext/fts5/fts5Int.h \
+   $(TOP)/ext/fts5/fts5_aux.c \
+   $(TOP)/ext/fts5/fts5_buffer.c \
+   $(TOP)/ext/fts5/fts5.c \
+   $(TOP)/ext/fts5/fts5_config.c \
+   $(TOP)/ext/fts5/fts5_expr.c \
+   $(TOP)/ext/fts5/fts5_index.c \
+   fts5parse.c \
+   $(TOP)/ext/fts5/fts5_storage.c 
+
 
 # Generated source code files
 #
@@ -684,6 +696,9 @@ wordcount$(EXE):    $(TOP)/test/wordcount.c sqlite3.c
 speedtest1$(EXE):      $(TOP)/test/speedtest1.c sqlite3.o
        $(TCC) -I. -o speedtest1$(EXE) $(TOP)/test/speedtest1.c sqlite3.o $(THREADLIB)
 
+loadfts: $(TOP)/tool/loadfts.c libsqlite3.a
+       $(TCC) $(TOP)/tool/loadfts.c libsqlite3.a -o loadfts $(THREADLIB)
+
 # This target will fail if the SQLite amalgamation contains any exported
 # symbols that do not begin with "sqlite3_". It is run as part of the
 # releasetest.tcl script.
index 84cd1f32f8f4e1bf265ae3fde7c97d08a92109c6..36de4c884485adc965b875d8084db40fa6ad5f26 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Add\stests\sand\sfixes\sfor\sbm25()\sfunction.
-D 2014-07-26T18:38:51.294
+C Add\sthe\s"loadfts"\sprogram,\sfor\sperformance\stesting\sthe\sloading\sof\sdata\sinto\sfts3/fts4/fts5\stables.
+D 2014-07-28T20:14:02.001
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in b03432313a3aad96c706f8164fb9f5307eaf19f5
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -106,10 +106,10 @@ F ext/fts3/unicode/mkunicode.tcl dc6f268eb526710e2c6e496c372471d773d0c368
 F ext/fts5/fts5.c 1496aff16dd9b0a013d14b6c8cf5b7df8c170abe
 F ext/fts5/fts5.h 8ace10d5b249a3baa983c79e7a1306d2a79cfd6a
 F ext/fts5/fts5Int.h 92fb9c4f759674ef569aebc338f363e167a8933c
-F ext/fts5/fts5_aux.c 78adc5db0ff4d6834df220ba6b3caa351d98b971
+F ext/fts5/fts5_aux.c 243156c197384e17983d6a3ed149fa2270b5bb85
 F ext/fts5/fts5_buffer.c 248c61ac9fec001602efc72a45704f3b8d367c00
-F ext/fts5/fts5_config.c 94f1b4cb4de6a7cd5780c14adb0198e289df8cef
-F ext/fts5/fts5_expr.c 65c1918002f2ec1755e4c0c28bf007659409fbd8
+F ext/fts5/fts5_config.c 2138741013e189724b5d40ea7af0f48952a44916
+F ext/fts5/fts5_expr.c e426baa54b9473cb31b8d891d7d1b923bfb5d017
 F ext/fts5/fts5_index.c 68d2d41b5c6d2f8838c3d6ebdc8b242718b8e997
 F ext/fts5/fts5_storage.c 2866e7e1de9dc851756c3a9c76b6e1d75e0facb7
 F ext/fts5/fts5parse.y 777da8e5819f75c217982c79c29d014c293acac9
@@ -156,7 +156,7 @@ F ext/rtree/viewrtree.tcl eea6224b3553599ae665b239bd827e182b466024
 F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
 F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
 F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60
-F main.mk cffc02a30f1af82d35410674f70a0286587add81
+F main.mk 8118631727a27fa88eb38a07ac3b86ecb86e9eb0
 F mkopcodec.awk c2ff431854d702cdd2d779c9c0d1f58fa16fa4ea
 F mkopcodeh.awk c6b3fa301db6ef7ac916b14c60868aeaec1337b5
 F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83
@@ -1158,6 +1158,7 @@ F tool/genfkey.test 4196a8928b78f51d54ef58e99e99401ab2f0a7e5
 F tool/getlock.c f4c39b651370156cae979501a7b156bdba50e7ce
 F tool/lemon.c 3ff0fec22f92dfb54e62eeb48772eddffdbeb0d6
 F tool/lempar.c 01ca97f87610d1dac6d8cd96ab109ab1130e76dc
+F tool/loadfts.c 3bdd46090112c84df44a4fbae740af3836108b3f
 F tool/logest.c eef612f8adf4d0993dafed0416064cf50d5d33c6
 F tool/mkautoconfamal.sh f8d8dbf7d62f409ebed5134998bf5b51d7266383
 F tool/mkkeywordhash.c dfff09dbbfaf950e89af294f48f902181b144670
@@ -1165,7 +1166,7 @@ F tool/mkopts.tcl 66ac10d240cc6e86abd37dc908d50382f84ff46e
 F tool/mkpragmatab.tcl 78a77b2c554d534c6f2dc903130186ed15715460
 F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97
 F tool/mksqlite3c-noext.tcl 1712d3d71256ca1f297046619c89e77a4d7c8f6d
-F tool/mksqlite3c.tcl ba274df71f5e6534b0a913c7c48eabfcbd0934b6
+F tool/mksqlite3c.tcl becaa9d5617dfe137e73dddda9dab8f58bc71e8c
 F tool/mksqlite3h.tcl ba24038056f51fde07c0079c41885ab85e2cff12
 F tool/mksqlite3internalh.tcl b6514145a7d5321b47e64e19b8116cc44f973eb1
 F tool/mkvsix.tcl 52a4c613707ac34ae9c226e5ccc69cb948556105
@@ -1196,7 +1197,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32
 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P c4d50428ab97f77e6721c4f8d03eaaf3ea91f3eb
-R 3301ccb2b839356242606883792ca77e
+P 71d32f53e81921e43c933cc968cb1c18d83fe1e0
+R 378763b2640fc19d9f72a0522c9f77b1
 U dan
-Z 456b4a2f1abc554b124e25c35490489e
+Z 3cf4ed481646bab9077300595c244e00
index 17caf8ac8b272df8659e2c424b90a4e25c4abb57..2f2c34352f67a34475b6b72935d759940a0158b0 100644 (file)
@@ -1 +1 @@
-71d32f53e81921e43c933cc968cb1c18d83fe1e0
\ No newline at end of file
+770b9540c19ad1e3d24adff382332bf032065efd
\ No newline at end of file
diff --git a/tool/loadfts.c b/tool/loadfts.c
new file mode 100644 (file)
index 0000000..18bd355
--- /dev/null
@@ -0,0 +1,204 @@
+/*
+** 2013-06-10
+**
+** The author disclaims copyright to this source code.  In place of
+** a legal notice, here is a blessing:
+**
+**    May you do good and not evil.
+**    May you find forgiveness for yourself and forgive others.
+**    May you share freely, never taking more than you give.
+**
+*************************************************************************
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <assert.h>
+#include <string.h>
+#include <errno.h>
+#include <dirent.h>
+#include "sqlite3.h"
+
+/*
+** Implementation of the "readtext(X)" SQL function.  The entire content
+** of the file named X is read and returned as a TEXT value. It is assumed
+** the file contains UTF-8 text. NULL is returned if the file does not 
+** exist or is unreadable.
+*/
+static void readfileFunc(
+  sqlite3_context *context,
+  int argc,
+  sqlite3_value **argv
+){
+  const char *zName;
+  FILE *in;
+  long nIn;
+  void *pBuf;
+
+  zName = (const char*)sqlite3_value_text(argv[0]);
+  if( zName==0 ) return;
+  in = fopen(zName, "rb");
+  if( in==0 ) return;
+  fseek(in, 0, SEEK_END);
+  nIn = ftell(in);
+  rewind(in);
+  pBuf = sqlite3_malloc( nIn );
+  if( pBuf && 1==fread(pBuf, nIn, 1, in) ){
+    sqlite3_result_text(context, pBuf, nIn, sqlite3_free);
+  }else{
+    sqlite3_free(pBuf);
+  }
+  fclose(in);
+}
+
+/*
+** Print usage text for this program and exit.
+*/
+static void showHelp(const char *zArgv0){
+  printf("\n"
+"Usage: %s SWITCHES... DB\n"
+"\n"
+"  This program opens the database named on the command line and attempts to\n"
+"  create an FTS table named \"fts\" with a single column. If successful, it\n"
+"  recursively traverses the directory named by the -dir option and inserts\n"
+"  the contents of each file into the fts table. All files are assumed to\n"
+"  contain UTF-8 text.\n"
+"\n"
+"Switches are:\n"
+"  -fts [345]       FTS version to use (default=5)\n"
+"  -idx [01]        Create a mapping from filename to rowid (default=0)\n"
+"  -dir <path>      Root of directory tree to load data from (default=.)\n"
+, zArgv0
+);
+  exit(1);
+}
+
+/*
+** Exit with a message based on the argument and the current value of errno.
+*/
+static void error_out(const char *zText){
+  fprintf(stderr, "%s: %s\n", zText, strerror(errno));
+  exit(-1);
+}
+
+/*
+** Exit with a message based on the first argument and the error message
+** currently stored in database handle db.
+*/
+static void sqlite_error_out(const char *zText, sqlite3 *db){
+  fprintf(stderr, "%s: %s\n", zText, sqlite3_errmsg(db));
+  exit(-1);
+}
+
+/*
+** Context object for visit_file().
+*/
+typedef struct VisitContext VisitContext;
+struct VisitContext {
+  sqlite3 *db;                    /* Database handle */
+  sqlite3_stmt *pInsert;          /* INSERT INTO fts VALUES(readtext(:1)) */
+};
+
+/*
+** Callback used with traverse(). The first argument points to an object
+** of type VisitContext. This function inserts the contents of the text
+** file zPath into the FTS table.
+*/
+void visit_file(void *pCtx, const char *zPath){
+  int rc;
+  VisitContext *p = (VisitContext*)pCtx;
+  /* printf("%s\n", zPath); */
+  sqlite3_bind_text(p->pInsert, 1, zPath, -1, SQLITE_STATIC);
+  sqlite3_step(p->pInsert);
+  rc = sqlite3_reset(p->pInsert);
+  if( rc!=SQLITE_OK ) sqlite_error_out("insert", p->db);
+}
+
+/*
+** Recursively traverse directory zDir. For each file that is not a 
+** directory, invoke the supplied callback with its path.
+*/
+static void traverse(
+  const char *zDir,               /* Directory to traverse */
+  void *pCtx,                     /* First argument passed to callback */
+  void (*xCallback)(void*, const char *zPath)
+){
+  DIR *d;
+  struct dirent *e;
+
+  d = opendir(zDir);
+  if( d==0 ) error_out("opendir()");
+
+  for(e=readdir(d); e; e=readdir(d)){
+    if( strcmp(e->d_name, ".")==0 || strcmp(e->d_name, "..")==0 ) continue;
+    char *zPath = sqlite3_mprintf("%s/%s", zDir, e->d_name);
+    if (e->d_type & DT_DIR) {
+      traverse(zPath, pCtx, xCallback);
+    }else{
+      xCallback(pCtx, zPath);
+    }
+    sqlite3_free(zPath);
+  }
+
+  closedir(d);
+}
+
+int main(int argc, char **argv){
+  int iFts = 5;                   /* Value of -fts option */
+  int bMap = 0;                   /* True to create mapping table */
+  const char *zDir = ".";         /* Directory to scan */
+  int i;
+  int rc;
+  sqlite3 *db;
+  char *zSql;
+  VisitContext sCtx;
+
+  if( argc % 2 ) showHelp(argv[0]);
+
+  for(i=1; i<(argc-1); i+=2){
+    char *zOpt = argv[i];
+    char *zArg = argv[i+1];
+    if( strcmp(zOpt, "-fts")==0 ){
+      iFts = atoi(zArg);
+      if( iFts!=3 && iFts!=4 && iFts!= 5) showHelp(argv[0]);
+    }
+    else if( strcmp(zOpt, "-idx")==0 ){
+      bMap = atoi(zArg);
+      if( bMap!=0 && bMap!=1 ) showHelp(argv[0]);
+    }
+    else if( strcmp(zOpt, "-dir")==0 ){
+      zDir = zArg;
+    }
+  }
+
+  /* Open the database file */
+  rc = sqlite3_open(argv[argc-1], &db);
+  if( rc!=SQLITE_OK ) sqlite_error_out("sqlite3_open()", db);
+
+  rc = sqlite3_create_function(db, "readtext", 1, SQLITE_UTF8, 0,
+                               readfileFunc, 0, 0);
+  if( rc!=SQLITE_OK ) sqlite_error_out("sqlite3_create_function()", db);
+
+  /* Create the FTS table */
+  zSql = sqlite3_mprintf("CREATE VIRTUAL TABLE fts USING fts%d(content)", iFts);
+  rc = sqlite3_exec(db, zSql, 0, 0, 0);
+  if( rc!=SQLITE_OK ) sqlite_error_out("sqlite3_exec(1)", db);
+  sqlite3_free(zSql);
+
+  /* Compile the INSERT statement to write data to the FTS table. */
+  memset(&sCtx, 0, sizeof(VisitContext));
+  sCtx.db = db;
+  rc = sqlite3_prepare_v2(db, 
+      "INSERT INTO fts VALUES(readtext(?))", -1, &sCtx.pInsert, 0
+  );
+  if( rc!=SQLITE_OK ) sqlite_error_out("sqlite3_prepare_v2(1)", db);
+
+  /* Load all files in the directory hierarchy into the FTS table. */
+  traverse(zDir, (void*)&sCtx, visit_file);
+
+  /* Clean up and exit. */
+  sqlite3_finalize(sCtx.pInsert);
+  sqlite3_close(db);
+  return 0;
+}
index 64207727be276e7d143a0ae66efb4f5100eed203..0d3120ce1af05be48ae827c771e5227e3c64915b 100644 (file)
@@ -97,6 +97,8 @@ foreach hdr {
    fts3Int.h
    fts3_hash.h
    fts3_tokenizer.h
+   fts5.h
+   fts5Int.h
    hash.h
    hwtime.h
    keywordhash.h
@@ -328,6 +330,15 @@ foreach file {
    fts3_unicode.c
    fts3_unicode2.c
 
+   fts5_aux.c
+   fts5_buffer.c
+   fts5.c
+   fts5_config.c
+   fts5_expr.c
+   fts5_index.c
+   fts5parse.c
+   fts5_storage.c
+
    rtree.c
    icu.c
    fts3_icu.c