fts3_tokenizer.c.svn-base
上传用户:sunhongbo
上传日期:2022-01-25
资源大小:3010k
文件大小:10k
源码类别:

数据库系统

开发平台:

C/C++

  1. /*
  2. ** 2007 June 22
  3. **
  4. ** The author disclaims copyright to this source code.  In place of
  5. ** a legal notice, here is a blessing:
  6. **
  7. **    May you do good and not evil.
  8. **    May you find forgiveness for yourself and forgive others.
  9. **    May you share freely, never taking more than you give.
  10. **
  11. ******************************************************************************
  12. **
  13. ** This is part of an SQLite module implementing full-text search.
  14. ** This particular file implements the generic tokenizer interface.
  15. */
  16. /*
  17. ** The code in this file is only compiled if:
  18. **
  19. **     * The FTS3 module is being built as an extension
  20. **       (in which case SQLITE_CORE is not defined), or
  21. **
  22. **     * The FTS3 module is being built into the core of
  23. **       SQLite (in which case SQLITE_ENABLE_FTS3 is defined).
  24. */
  25. #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3)
  26. #include "sqlite3ext.h"
  27. #ifndef SQLITE_CORE
  28.   SQLITE_EXTENSION_INIT1
  29. #endif
  30. #include "fts3_hash.h"
  31. #include "fts3_tokenizer.h"
  32. #include <assert.h>
  33. /*
  34. ** Implementation of the SQL scalar function for accessing the underlying 
  35. ** hash table. This function may be called as follows:
  36. **
  37. **   SELECT <function-name>(<key-name>);
  38. **   SELECT <function-name>(<key-name>, <pointer>);
  39. **
  40. ** where <function-name> is the name passed as the second argument
  41. ** to the sqlite3Fts3InitHashTable() function (e.g. 'fts3_tokenizer').
  42. **
  43. ** If the <pointer> argument is specified, it must be a blob value
  44. ** containing a pointer to be stored as the hash data corresponding
  45. ** to the string <key-name>. If <pointer> is not specified, then
  46. ** the string <key-name> must already exist in the has table. Otherwise,
  47. ** an error is returned.
  48. **
  49. ** Whether or not the <pointer> argument is specified, the value returned
  50. ** is a blob containing the pointer stored as the hash data corresponding
  51. ** to string <key-name> (after the hash-table is updated, if applicable).
  52. */
  53. static void scalarFunc(
  54.   sqlite3_context *context,
  55.   int argc,
  56.   sqlite3_value **argv
  57. ){
  58.   fts3Hash *pHash;
  59.   void *pPtr = 0;
  60.   const unsigned char *zName;
  61.   int nName;
  62.   assert( argc==1 || argc==2 );
  63.   pHash = (fts3Hash *)sqlite3_user_data(context);
  64.   zName = sqlite3_value_text(argv[0]);
  65.   nName = sqlite3_value_bytes(argv[0])+1;
  66.   if( argc==2 ){
  67.     void *pOld;
  68.     int n = sqlite3_value_bytes(argv[1]);
  69.     if( n!=sizeof(pPtr) ){
  70.       sqlite3_result_error(context, "argument type mismatch", -1);
  71.       return;
  72.     }
  73.     pPtr = *(void **)sqlite3_value_blob(argv[1]);
  74.     pOld = sqlite3Fts3HashInsert(pHash, (void *)zName, nName, pPtr);
  75.     if( pOld==pPtr ){
  76.       sqlite3_result_error(context, "out of memory", -1);
  77.       return;
  78.     }
  79.   }else{
  80.     pPtr = sqlite3Fts3HashFind(pHash, zName, nName);
  81.     if( !pPtr ){
  82.       char *zErr = sqlite3_mprintf("unknown tokenizer: %s", zName);
  83.       sqlite3_result_error(context, zErr, -1);
  84.       sqlite3_free(zErr);
  85.       return;
  86.     }
  87.   }
  88.   sqlite3_result_blob(context, (void *)&pPtr, sizeof(pPtr), SQLITE_TRANSIENT);
  89. }
  90. #ifdef SQLITE_TEST
  91. #include <tcl.h>
  92. #include <string.h>
  93. /*
  94. ** Implementation of a special SQL scalar function for testing tokenizers 
  95. ** designed to be used in concert with the Tcl testing framework. This
  96. ** function must be called with two arguments:
  97. **
  98. **   SELECT <function-name>(<key-name>, <input-string>);
  99. **   SELECT <function-name>(<key-name>, <pointer>);
  100. **
  101. ** where <function-name> is the name passed as the second argument
  102. ** to the sqlite3Fts3InitHashTable() function (e.g. 'fts3_tokenizer')
  103. ** concatenated with the string '_test' (e.g. 'fts3_tokenizer_test').
  104. **
  105. ** The return value is a string that may be interpreted as a Tcl
  106. ** list. For each token in the <input-string>, three elements are
  107. ** added to the returned list. The first is the token position, the 
  108. ** second is the token text (folded, stemmed, etc.) and the third is the
  109. ** substring of <input-string> associated with the token. For example, 
  110. ** using the built-in "simple" tokenizer:
  111. **
  112. **   SELECT fts_tokenizer_test('simple', 'I don't see how');
  113. **
  114. ** will return the string:
  115. **
  116. **   "{0 i I 1 dont don't 2 see see 3 how how}"
  117. **   
  118. */
  119. static void testFunc(
  120.   sqlite3_context *context,
  121.   int argc,
  122.   sqlite3_value **argv
  123. ){
  124.   fts3Hash *pHash;
  125.   sqlite3_tokenizer_module *p;
  126.   sqlite3_tokenizer *pTokenizer = 0;
  127.   sqlite3_tokenizer_cursor *pCsr = 0;
  128.   const char *zErr = 0;
  129.   const char *zName;
  130.   int nName;
  131.   const char *zInput;
  132.   int nInput;
  133.   const char *zArg = 0;
  134.   const char *zToken;
  135.   int nToken;
  136.   int iStart;
  137.   int iEnd;
  138.   int iPos;
  139.   Tcl_Obj *pRet;
  140.   assert( argc==2 || argc==3 );
  141.   nName = sqlite3_value_bytes(argv[0]);
  142.   zName = (const char *)sqlite3_value_text(argv[0]);
  143.   nInput = sqlite3_value_bytes(argv[argc-1]);
  144.   zInput = (const char *)sqlite3_value_text(argv[argc-1]);
  145.   if( argc==3 ){
  146.     zArg = (const char *)sqlite3_value_text(argv[1]);
  147.   }
  148.   pHash = (fts3Hash *)sqlite3_user_data(context);
  149.   p = (sqlite3_tokenizer_module *)sqlite3Fts3HashFind(pHash, zName, nName+1);
  150.   if( !p ){
  151.     char *zErr = sqlite3_mprintf("unknown tokenizer: %s", zName);
  152.     sqlite3_result_error(context, zErr, -1);
  153.     sqlite3_free(zErr);
  154.     return;
  155.   }
  156.   pRet = Tcl_NewObj();
  157.   Tcl_IncrRefCount(pRet);
  158.   if( SQLITE_OK!=p->xCreate(zArg ? 1 : 0, &zArg, &pTokenizer) ){
  159.     zErr = "error in xCreate()";
  160.     goto finish;
  161.   }
  162.   pTokenizer->pModule = p;
  163.   if( SQLITE_OK!=p->xOpen(pTokenizer, zInput, nInput, &pCsr) ){
  164.     zErr = "error in xOpen()";
  165.     goto finish;
  166.   }
  167.   pCsr->pTokenizer = pTokenizer;
  168.   while( SQLITE_OK==p->xNext(pCsr, &zToken, &nToken, &iStart, &iEnd, &iPos) ){
  169.     Tcl_ListObjAppendElement(0, pRet, Tcl_NewIntObj(iPos));
  170.     Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj(zToken, nToken));
  171.     zToken = &zInput[iStart];
  172.     nToken = iEnd-iStart;
  173.     Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj(zToken, nToken));
  174.   }
  175.   if( SQLITE_OK!=p->xClose(pCsr) ){
  176.     zErr = "error in xClose()";
  177.     goto finish;
  178.   }
  179.   if( SQLITE_OK!=p->xDestroy(pTokenizer) ){
  180.     zErr = "error in xDestroy()";
  181.     goto finish;
  182.   }
  183. finish:
  184.   if( zErr ){
  185.     sqlite3_result_error(context, zErr, -1);
  186.   }else{
  187.     sqlite3_result_text(context, Tcl_GetString(pRet), -1, SQLITE_TRANSIENT);
  188.   }
  189.   Tcl_DecrRefCount(pRet);
  190. }
  191. static
  192. int registerTokenizer(
  193.   sqlite3 *db, 
  194.   char *zName, 
  195.   const sqlite3_tokenizer_module *p
  196. ){
  197.   int rc;
  198.   sqlite3_stmt *pStmt;
  199.   const char zSql[] = "SELECT fts3_tokenizer(?, ?)";
  200.   rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
  201.   if( rc!=SQLITE_OK ){
  202.     return rc;
  203.   }
  204.   sqlite3_bind_text(pStmt, 1, zName, -1, SQLITE_STATIC);
  205.   sqlite3_bind_blob(pStmt, 2, &p, sizeof(p), SQLITE_STATIC);
  206.   sqlite3_step(pStmt);
  207.   return sqlite3_finalize(pStmt);
  208. }
  209. static
  210. int queryTokenizer(
  211.   sqlite3 *db, 
  212.   char *zName,  
  213.   const sqlite3_tokenizer_module **pp
  214. ){
  215.   int rc;
  216.   sqlite3_stmt *pStmt;
  217.   const char zSql[] = "SELECT fts3_tokenizer(?)";
  218.   *pp = 0;
  219.   rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
  220.   if( rc!=SQLITE_OK ){
  221.     return rc;
  222.   }
  223.   sqlite3_bind_text(pStmt, 1, zName, -1, SQLITE_STATIC);
  224.   if( SQLITE_ROW==sqlite3_step(pStmt) ){
  225.     if( sqlite3_column_type(pStmt, 0)==SQLITE_BLOB ){
  226.       memcpy(pp, sqlite3_column_blob(pStmt, 0), sizeof(*pp));
  227.     }
  228.   }
  229.   return sqlite3_finalize(pStmt);
  230. }
  231. void sqlite3Fts3SimpleTokenizerModule(sqlite3_tokenizer_module const**ppModule);
  232. /*
  233. ** Implementation of the scalar function fts3_tokenizer_internal_test().
  234. ** This function is used for testing only, it is not included in the
  235. ** build unless SQLITE_TEST is defined.
  236. **
  237. ** The purpose of this is to test that the fts3_tokenizer() function
  238. ** can be used as designed by the C-code in the queryTokenizer and
  239. ** registerTokenizer() functions above. These two functions are repeated
  240. ** in the README.tokenizer file as an example, so it is important to
  241. ** test them.
  242. **
  243. ** To run the tests, evaluate the fts3_tokenizer_internal_test() scalar
  244. ** function with no arguments. An assert() will fail if a problem is
  245. ** detected. i.e.:
  246. **
  247. **     SELECT fts3_tokenizer_internal_test();
  248. **
  249. */
  250. static void intTestFunc(
  251.   sqlite3_context *context,
  252.   int argc,
  253.   sqlite3_value **argv
  254. ){
  255.   int rc;
  256.   const sqlite3_tokenizer_module *p1;
  257.   const sqlite3_tokenizer_module *p2;
  258.   sqlite3 *db = (sqlite3 *)sqlite3_user_data(context);
  259.   /* Test the query function */
  260.   sqlite3Fts3SimpleTokenizerModule(&p1);
  261.   rc = queryTokenizer(db, "simple", &p2);
  262.   assert( rc==SQLITE_OK );
  263.   assert( p1==p2 );
  264.   rc = queryTokenizer(db, "nosuchtokenizer", &p2);
  265.   assert( rc==SQLITE_ERROR );
  266.   assert( p2==0 );
  267.   assert( 0==strcmp(sqlite3_errmsg(db), "unknown tokenizer: nosuchtokenizer") );
  268.   /* Test the storage function */
  269.   rc = registerTokenizer(db, "nosuchtokenizer", p1);
  270.   assert( rc==SQLITE_OK );
  271.   rc = queryTokenizer(db, "nosuchtokenizer", &p2);
  272.   assert( rc==SQLITE_OK );
  273.   assert( p2==p1 );
  274.   sqlite3_result_text(context, "ok", -1, SQLITE_STATIC);
  275. }
  276. #endif
  277. /*
  278. ** Set up SQL objects in database db used to access the contents of
  279. ** the hash table pointed to by argument pHash. The hash table must
  280. ** been initialised to use string keys, and to take a private copy 
  281. ** of the key when a value is inserted. i.e. by a call similar to:
  282. **
  283. **    sqlite3Fts3HashInit(pHash, FTS3_HASH_STRING, 1);
  284. **
  285. ** This function adds a scalar function (see header comment above
  286. ** scalarFunc() in this file for details) and, if ENABLE_TABLE is
  287. ** defined at compilation time, a temporary virtual table (see header 
  288. ** comment above struct HashTableVtab) to the database schema. Both 
  289. ** provide read/write access to the contents of *pHash.
  290. **
  291. ** The third argument to this function, zName, is used as the name
  292. ** of both the scalar and, if created, the virtual table.
  293. */
  294. int sqlite3Fts3InitHashTable(
  295.   sqlite3 *db, 
  296.   fts3Hash *pHash, 
  297.   const char *zName
  298. ){
  299.   int rc = SQLITE_OK;
  300.   void *p = (void *)pHash;
  301.   const int any = SQLITE_ANY;
  302.   char *zTest = 0;
  303.   char *zTest2 = 0;
  304. #ifdef SQLITE_TEST
  305.   void *pdb = (void *)db;
  306.   zTest = sqlite3_mprintf("%s_test", zName);
  307.   zTest2 = sqlite3_mprintf("%s_internal_test", zName);
  308.   if( !zTest || !zTest2 ){
  309.     rc = SQLITE_NOMEM;
  310.   }
  311. #endif
  312.   if( rc!=SQLITE_OK
  313.    || (rc = sqlite3_create_function(db, zName, 1, any, p, scalarFunc, 0, 0))
  314.    || (rc = sqlite3_create_function(db, zName, 2, any, p, scalarFunc, 0, 0))
  315. #ifdef SQLITE_TEST
  316.    || (rc = sqlite3_create_function(db, zTest, 2, any, p, testFunc, 0, 0))
  317.    || (rc = sqlite3_create_function(db, zTest, 3, any, p, testFunc, 0, 0))
  318.    || (rc = sqlite3_create_function(db, zTest2, 0, any, pdb, intTestFunc, 0, 0))
  319. #endif
  320.   );
  321.   sqlite3_free(zTest);
  322.   sqlite3_free(zTest2);
  323.   return rc;
  324. }
  325. #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */